技術メモ

プログラミングとか電子工作とか

Elixir入門(第九章 再帰)

f:id:ysmn_deus:20190122112104p:plain

どうも、靖宗です。
今回のテーマはRecursion(再帰)です。
アルゴリズミックな感じがして「逃げろ!」という気がしないでもないんですが、チュートリアルでしばきまわされることは無いと信じて進みます。

Loops through recursion(再帰ループ?)

一般的に関数型言語ではループの書き方が違うそうで。しらなんだ。
例えば、C言語でのループは以下のようにかける。

for(i = 0; i < sizeof(array); i++) {
  array[i] = array[i] * 2;
}

せやな。という感じである。
ただし、関数型言語は変数が変わっていくのを嫌うっぽい(間違ってたらすみません)ので、実行中にarrayとiが絶え間なく変わっていくのが気にくわない?

Elixirではループはこう書く。

defmodule Recursion do
  def print_multiple_times(msg, n) when n <= 1 do
    IO.puts msg
  end

  def print_multiple_times(msg, n) do
    IO.puts msg
    print_multiple_times(msg, n - 1)
  end
end

Recursion.print_multiple_times("Hello!", 3)
# Hello!
# Hello!
# Hello!

引数nで条件分岐するよう一個目の関数の宣言の所にgurad句が書かれている。
guard句に引っかからなければ、再帰の関数が呼び出される仕組み。
そのときにnが1ずつへっていくので、そのうち再帰の関数が呼び出されなくなるという仕組みです。
たぶんcondで書いても行けそう。やってみる。

defmodule Recursion do
  def print_multiple_times(msg, n) do
    cond do
      n <= 1 ->
        IO.puts msg
      true ->
        IO.puts msg
        print_multiple_times(msg, n - 1)
    end
  end
end
PS > iex.bat .\math.exs
Interactive Elixir (1.8.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Recursion.print_multiple_times("Hello!", 3)
Hello!
Hello!
Hello!
:ok

なんか変なアトムが返ってきてるけど、元の形でも返ってきてるのでとりあえず今は放置。

Reduce and map algorithms(リデュースとマップアルゴリズム

並列化プログラミングの時に出てくるアレだと思います。(そこまでくわしくない)
とりあえずサンプルを見ていきます。

defmodule Math do
  def sum_list([head | tail], accumulator) do
    sum_list(tail, head + accumulator)
  end

  def sum_list([], accumulator) do
    accumulator
  end
end

IO.puts Math.sum_list([1, 2, 3], 0) #=> 6

総和を再帰で書くとこうなる、というお手本みたいなコード。
headを足していって最後のリストが空になったら総和を返すみたいな感じ。
こういうパターンをreduce algorithmと言うそうです。

足し算(引き算も同様)が出てきたので、かけ算は?
全ての値を二倍にする関数

defmodule Math do
  def double_each([head | tail]) do
    [head * 2 | double_each(tail)]
  end

  def double_each([]) do
    []
  end
end
[head * 2 | 関数(tail)]
[head * 2 | [head * 2 | 関数(tail)]]
[head * 2 | [head * 2 | [head * 2 | 関数(tail)]]]
...
みたいなイメージ?

なるほど。総和の関数もそうだったのですが、リストの実装がうまいこと生きてきてる気がする。
こういうパターンをmap algorithmと言うそうです。いろんな言語にあるhoge.map(list)みたいなイメージかな。

最後の方に「Enum使うと上の奴こう書けるで」ってありますが。次回に回します。
ぱっと見めっちゃ便利そう・・・