処理の大半は、同一の処理を共有したいけど、一部だけ挙動を変えたい、といったとき、関数を引数で渡すテクニックが、役に立つ
下記の例は、HTTP GETでJSON API結果を拾った後に、list_mapを加工する関数を引数渡しして、加工後を返す例
defmodule Json do
def get( domain, path, header \\ [], map_function \\ &nop/1 ) do
domain <> path
|> HTTPoison.get!( header )
|> parse( map_function )
end
defp parse( response, map_function ) do
response
|> get_body
|> Poison.decode!
|> map_function.()
end
defp get_body( %{ status_code: 200, body: body } ), do: body
defp nop( map_list ), do: map_list
end
呼び出し側は、こんな感じで、「&」とアリティ付きで指定する(未指定時は、デフォルト引数で無加工の関数が呼ばれる)
defmodule GithubWrapper do
def run(), do: Json.get( "https://api.github.com", "/rate_limit", &pick_rate/1 )
defp pick_rate( %{ "rate" => rate } ), do: rate
end
無名関数って、Enum.map()等の高階関数の中で使うケースは多いけど、function.()の形式で使うことは少ないんだが、上記みたいなライブラリ/FW側を作るときには、案外、重宝する
あと、こうしたケースをスマートに書くには、「渡す関数の引数を1個に限定する」という、モナドっぽい考え方がコツ