Elixir 練習問題 ListsAndRecursion-1

defmodule MyList do

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

  def reduce([], value, _func) do
    value
  end
  def reduce([head|tail], value, func) do
    reduce(tail, func.(head, value), func)
  end

  def mapsum(list, func) do
    map(list, func)
    |> reduce(0, &(&1 + &2))
  end

end
^o^ > iex practice_7_1.exs
Eshell V8.0  (abort with ^G)
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> MyList.mapsum([1, 2, 3], &(&1 * &1))
14

Elixir ではクロージャは作れない?

Elixir の関数は、関数を返すことができて、その関数は元の環境を覚えている。だからこないだのエントリでは「クロージャだ」と書いた。
だけど、今日になって違うんじゃないかと思うようになった。というのは、返ってきた関数は確かに元の環境を覚えているけど変更はできないみたいだからだ。
例えば、JavaScript で典型的なクロージャを書いてみよう。下の make_counter 関数の返す関数は、呼び出されるごとに 1 ずつ大きな数を返す。

function make_counter(init) {
  var count = init;
  return function() {
    count = count + 1;
    return count
  }
}

var counter = make_counter(0);
console.log(counter());
console.log(counter());
console.log(counter());
^o^ > node counter.js
1
2
3

Elixir で同じように書いてみよう。

defmodule Counter do

  def make(init) do
    count = init
    fn ->
      count = count + 1
      count
    end
  end
end

counter = Counter.make(0)
IO.puts counter.()
IO.puts counter.()
IO.puts counter.()

見てわかるように、JavaScript のコードをほぼそのまま Elixir で書き直したものだ。ところが、これを実行してみると:

^o^ > elixir counter.exs
1
1
1

このとおり、関数を何度呼び出しても数が増えていかない。
これって、やっぱりクロージャとは言わないんじゃ?それとも何か間違ってる?