[Elixir]引数で与えられた関数を実行する

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

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s