Elixirで、引数として関数 fn を与えた時、その与えられた関数を実行する方法がぱっと調べただけでは見つからなかったのでメモ。
以下のように、 f.() という形式で、与えられた引数としての関数を実施できるようですね。
簡単なサンプル
defmodule Simple do
def call(f) do
f.()
end
end
iex(1)> Simple.call fn() -> IO.puts "Hello" end
Hello
:ok
もう少し進んで、exercismから同様な問題があったのでそれを使って見てみます。
テストコード
defmodule ListOpsTest do
alias ListOps, as: L
use ExUnit.Case, async: true
defp odd?(n), do: rem(n, 2) == 1
# 引数として、 &odd?/1 という関数を与える。
# &odd?/1 は、引数を1つ与えることができる。
test "filter of normal list" do
assert L.filter([1,2,3,4], &odd?/1) == [1,3]
end
# 引数として、 &(&1+1) という引数込みの処理系を与える
# &1 なので、この与えた関数は、関数自身が1つの引数を期待する。
test "map of normal list" do
assert L.map([1,3,5,7], &(&1+1)) == [2,4,6,8]
end
end
実行コード
defmodule ListOps do
# filter(l, f) に与えられた関数 f に対して、 f.(head) として引数を1つ与えて実行する
def filter(l, f) do
Enum.reduce(l, [], fn(head, acc) -> (if f.(head), do: [acc, head], else: acc)end)
|> List.flatten
end
# map(l, f) に与えられた関数 f に対して、 f.(head) として引数を1つ与えて実行する
def map(l, f) do
Enum.reduce(l, [], fn(head, acc) -> [acc, f.(head)] end)
|> List.flatten
end
end
Rubyでいう、 yield を呼び出すのをElixirでは .() で行うのですね。
参考: http://hashrocket.com/blog/posts/elixir-functions-ruby-lambdas