[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

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中