プログラミング Elixir 確認メモ (1)

とりあえずメモを控え。あと markdown の preview をコピペとか色々微妙 (こら


ドキュメント

ListsAndRecursion-5

とりあえず Enum.all? から。使用例として挙げられているのが以下でした。

> Enum.all?(list, &(&1 < 4))
false

list は以下な定義です。

> list = Enum.to_list 1..5
[1, 2, 3, 4, 5]

うーん、、、if 使うと簡単なんですが他の方法ないのかしら。

defmodule EnumExcercise do
  def all?([], _func) do
    true
  end
  def all?([head|tail], func) do
    if func.(head) do
        all?(tail, func)
    else
        false
    end
  end
end

こうかしら。

defmodule EnumExcercise do
  def all?([], _func) do
    true
  end
  def all?([head|tail], func) do
    _all?(func.(head), tail, func)
  end
  def _all?(false, _list, _func) do
    false
  end
  def _all?(true, list, func) do
    all?(list, func)
  end
end

次、Enum.each ですがこれどこで例示されているのやら。と思ったら単純に list に関数を適用すれば良いのかしら。

  def each([], _func), do: []
  def each([head|tail], func) do
    [func.(head)|each(tail, func)]
  end

次、Enum.filter て何かしら。

> Enum.filster([1, 2, 3, 4, 5], &(&1 > 2))
[3, 4, 5]

これも簡単。

  def filter([], _func), do: []
  def filter([head|tail], func) do
    if func.(head) do
      [head|filter(tail, func)]
    else
      filter(tail, func)
    end
  end

リスト走査て SICP 以来で懐しい。次は split とのこと。例示されているのが以下。

> Enum.split([1, 2, 3, 4, 5], 3)
{[1, 2, 3], [4, 5]}

tuple になってるのか。どうやるんだろ。

  • tuple を戻す

  • 引数ごとでリストを分割

こんなことができるのか。

[first, second, third|tail] = list

でもこれ、要素数が合わないと駄目みたい。こまったなと言いつつ探してみたら以下なナニが出てきた。

  def split(list, num) do
    _split([], list, num)
  end

  defp _split(taken, remaining, 0) do
    { taken, remaining }
  end

  defp _split(taken, [remaining_head | remaining_tail], num) do
    _split(taken ++ [remaining_head], remaining_tail, num - 1)
  end

ええとこれ、num が 0 になったら終わるよね。てことは

defp _split(taken, [], 0) do
end

なソレがあれば良いのかな。で、どハマッた挙句に以下がでっちあがりました。

  def split(list, num) do
    _split([], [], list, num, num)
  end

  # result が空でリスト終了
  defp _split([], splited, [], _count, _num) do
    {splited}
  end

  # リスト終了
  defp _split(result, splited, [], _count, _num) do
    List.to_tuple(result ++ [splited])
  end

  # 最初
  defp _split([], [], [remaining_head|remaining_tail], count, num) do
    _split([], [remaining_head], remaining_tail, count-1, num)
  end

  # result が空で count が 0
  defp _split([], splited, [remaining_head|remaining_tail], 0, num) do
    _split([splited], [], [remaining_head|remaining_tail], num, num)
  end

  # result が空
  defp _split([], splited, [remaining_head|remaining_tail], count, num) do
    _split([], splited ++ [remaining_head], remaining_tail, count - 1, num)
  end

  # count が 0
  defp _split(result, splited, [remaining_head|remaining_tail], 0, num) do
    _split(result ++ [splited], [remaining_head], remaining_tail, num, num)
  end

  defp _split(result, splited, [remaining_head|remaining_tail], count, num) do
    _split(result, splited ++ [remaining_head], remaining_tail, count - 1, num)
  end

List.to_tuple 使わざるを得ず。。。

つづき

ModulesAndFundtions-7

浮動小数点数を二つの 10 進数文字列に変換
Erlang な模様。どうやって探すのかと。以下?

これで良いのかしら

> :erlang.float_to_list(3.14, [:short])
~c"3.14"

ファイル名の拡張子を取り出す
これは Elixir の extname で良いのかしら。

> Path.extname("dave/test.exs")
".exs"

プロセスの現在の作業ディレクトリを戻す
Elixir の、とのこと。探し方がいまひとつ微妙。

> File.cwd
{:ok, "/root"}

JSON 文字列を Elixir データ構造に変換
これは見つけるだけで良いとのこと。poison てのがある、とのこと。

オペレーティングシステムのシェルでコマンドを実行
これ、System.cmd なのかしら。と思ったらなんか叱られた。System.shell な模様。

> System.shell("echo hello")
{"hello\n", 0}

ListsAndRecursion-1

List/Scheme 風で考え易い。実装以下。

defmodule MyList do
  def mapsum([], _func) do
    0
  end
  def mapsum([head|tail], func) do
    func.(head) + mapsum(tail, func)
  end
end

でコンパイルして実行。

> MyList.mapsum([1, 2, 3], &(&1*&1))
14

ListsAndRecursion-2

リストの要素の最大値を返す max(list) を、とのこと。最大値か。。つうか Enum.max てのがあるようですが。。。

defmodule MyList do
  def max([head|tail]) do
    _max(head, tail)
  end
  def _max(max_value, []) do
    max_value
  end
  def _max(max_value, [head|tail]) do
    _max(if(head > max_value, do: head, else: max_value), tail)
  end
end

どうやるのかしらと思ってたら if は関数とのこと。ややトリッキー、ってのはこのあたりなのかしら。

ListsAndRecursion-3

微妙なのがでっちあがりました。

defmodule MyList do
  def ceasar([], _n) do
    []
  end
  def ceasar([head|tail], n) do
    [if(head+n > 122, do: 96 + (head+n-122), else: head+n)|ceasar(tail, n)]
  end
end

絶対これ微妙。出力はあってるみたいですが。。。

> MyList.ceasar('ryvkve', 13)
~c"elixir"

ListsAndRecursion-4

これで良いのかしら。

defmodule MyList do
  def span(to, to), do: [to]
  def span(from, to) do
    [from | span(from+1, to)]
  end
end

一応大丈夫、なのかどうか。

> MyList.span(1, 5)
[1, 2, 3, 4, 5]

つうか、パタンマッチ強力ですね。

chapter.12 までは

iex で云々します。あと vscode で C-j が改行に割り当てられてるの何とかせねば。

キーバインド削除で

何とかなりました。

練習問題1

> list_concat = fn l1, l2 -> l1 ++ l2 end
> list_concat.([:a, :b], [:c, :d])
[:a, :b, :c, :d]
> sum = fn a, b, c -> a + b + c end
> sum.(1, 2, 3)
6
> pair_tuple_to_list = fn {p1, p2} -> [p1, p2] end
> > pair_tuple_to_list.({1234, 5678})
[1234, 5678]

練習問題2

> functions2 = fn
...> {0, 0, _} -> "FizzBuzz"
...> {0, _, _} -> "Fizz"
...> {_, 0, _} -> "Buzz"
...> {_, _, x} -> "#{x}"
...> end
> functions2.({0, 0, 1})
"FizzBuzz"
> functions2.({0, 1, 1})
"Fizz"
> functions2.({1, 0, 1})
"Buzz"
> functions2.({1, 1, 1})
"1"

練習問題3

> functions3 = fn n -> functions2.({rem(n, 3), rem(n, 5), n}) end
> functions3.(10)
"Buzz"
> functions3.(11)
"11"
> functions3.(12)
"Fizz"
> functions3.(13)
"13"
> functions3.(14)
"14"
> functions3.(15)
"FizzBuzz"
> functions3.(16)
"16"

練習問題4

こうだった

prefix = fn first -> (fn second -> "#{first} #{second}" end) end

文字列の扱いがアレ。

練習問題5

> Enum.map [1, 2, 3, 4], fn x -> x + 2 end
[3, 4, 5, 6]
> Enum.map [1, 2, 3, 4], &(&1 + 2)
[3, 4, 5, 6]

あるいは

> Enum.map [1, 2, 3, 4], fn x -> IO.inspect x end
1
2
3
4
[1, 2, 3, 4]
> Enum.map [1, 2, 3, 4], &(IO.inspect &1) 
1
2
3
4
[1, 2, 3, 4]

モジュールのコンパイル (練習問題)

注意。mm ディレクトリに times.exs があるとすると

c "mm/times.exs"

でないと駄目。

再起

定義の順番が重要とのこと。

defmodule Factorial do
  def of(0), do: 1
  def of(n), do: n * of(n - 1)
end

ModulesAndFunctions-6

考え方としては?

  • range な引数はパタンマッチで取得できる?

    • def guess(actual, start..end) (別途確認

  • end が actual より大きいかどうか、を判定する手続きが必要?

  • 大きければ end を 2 で割ったナニ

推測値? ってどうやって取得するのかと。。。ヘルパ関数でアレなのかな。
(actual が 273 の場合)

  • 1 と 1000 の場合、推測値は真ん中

最初が色々大変だった

  • aquaskk 入れるの大変でした

    • homebrew 導入

    • brew install --cask aquaskk

    • 再起動

    • keyboard - input sources から skk 追加

  • docker desksop とか vscode とか入れた

  • latest な elixir 向け Dockerfile 入手して起動

とりあえずカレントディレクトリとファイル共有。

$ docker run -it -v .:/root 5fa37d9ab3a2 bash


この記事が気に入ったらサポートをしてみませんか?