1. OverView
ここまでの説名で、散々使っといて、今更、どの面下げて解説すりゃいいんでしょうねぇ。
と、思いつつ、書くことたくさんあるので、ここも随時分割していきたいと思います。
Elixir Schoolの説明順に問題があると考えて始めたこの企画ですが、うーん、昨今の言語だと
しかたないのかな、と言う気がしてきました。関数の使い方と引数である型を覚えないと、サンプル書いても
訳がわかんないんだよね。
2 まずは解説
2.1 匿名関数(Anonymous Functions)
匿名関数です。無名変数とも呼ばれます。
これ、ここまでの説明でも頻発しましたが、
fn (引数) -> 関数本体 end
と言う定義になります。
sum = fn (a, b) -> a + b end
sum.(2, 3)
5
そして、省略記法があります。
sum = &(&1 + &2)
sum.(2, 3)
5
省略記法では、引数は&1, &2と省略して書けます。
引数、シェル言語が?貴様?と思いますが、enum何かだと御世話になりますね。
iex(23)> Enum.map([0, 1, 2, 3], fn(x) -> x * 5 end)
[0, 5, 10, 15]
iex(24)> Enum.map([0, 1, 2, 3], &(&1 * 5))
[0, 5, 10, 15]
iex(25)>
fn ~ endとくらい書けよ、みたいな話をおいておくと、ここでわざわざxと言う変数を定義せずに済むので
無駄に言いありげな変数名を乱発しないので、逆に可読性が上がると思います。
2.2 パターンマッチ
さて、Elixir Schoolを見てみましょう。
Elixirではパターンマッチは変数だけに限定されているわけではなく、次の項にあるように、関数へと適用することができます。
Elixirはパターンマッチを用いてマッチする可能性のある全てのオプションをチェックし、最初にマッチするオプションを選択して実行します:
handle_result = fn
{:ok, result} -> IO.puts "Handling result..."
{:ok, _} -> IO.puts "This would be never run as previous will be matched beforehand."
{:error} -> IO.puts "An error has occurred!"
end
関数の引数で、それぞれ実行される本体が変わってくるんですね。
あー、これで、check_ok_with_resultとかcheck_errorとか引数ごとに別の関数を作らなくて済むと言ううれしい話。
iex(79)> handle_result.({:ok, some_result})
Handling result...
:ok
iex(81)> handle_result.({:error})
An error has occurred!
:ok
引数に合わせて、結果が変わっているのがわかるでしょうか?
2.3 名前付き関数
モジュールは次回やるので、今回はモジュールはおいておきます。
ざっと説明するとdefmoduleでモジュールを定義して、その中に関数を作ります。
defmodule Greeter do
def hello(name) do
"Hello, " <> name
end
end
はい、def 関数名(引数) do ~ endですね。
この、関数名で、関数が呼び出せます。
Greeter.hello("Sean")
"Hello, Sean"
ついでに、
関数本体が1行で済むなら、 do: を使ってより短くすることができます:
defmodule Greeter do
def hello(name), do: "Hello, " <> name
end
さて、ここまでコピペですが、ここでがっつり解説となります。
2.4 本日分だけでも、とっても再帰が簡単ですね。
defmodule Length do
def of([]), do: 0
def of([_ | tail]), do: 1 + of(tail)
end
さて、名前付きですが、パターンマッチ、関数本体が1行で済むなら、 do: を使ってより短くを使って、簡潔に
再帰処理をしております。
Lengthモジュールのofを、引数[]で呼び出し…
Length.of [1, 2, 3]
3
さて、関数の中身ですが、
def of([]), do: 0 <-これは、終了処理です
def of([_ | tail]), do: 1 + of(tail) これが、計算する本体
_ | tailは、以下の様にマッチします。
実行回数 | 関数の戻り値 | 説明 |
---|---|---|
初回 | 1 | tail(2,3) of(2,3)が、呼び出す |
2回 | 2 | tail(3) of(3)が、呼び出す |
3回 | 3 | tail(nil) of(nil)が呼び出す -> これが戻り値となる |
4回目 | 3 | 引数がnilなので、加算せずに、do:0が実行される |
以上の様に、再帰が非常に簡潔に書けます。
いやぁ、便利便利。いろんな記法を覚えた甲斐がありますな。
まぁ、実際にはEnumを使うんでしょうがね。
3. 本日のチートシート
関数名 | 説明 | 例 |
---|---|---|
匿名関数(Anonymous Functions) | fn (引数) -> 関数本体 endで定義する | sum = fn (a, b) -> a + b end sum.(2, 3) 5 |
匿名関数の省略記法 | &()で関数を囲む、引数は&1,&2...となる | sum = &(&1 + &2) sum.(2, 3) 5 |
関数の引数のパターンマッチ | パターンマッチは関数へと適用することが出来る | handle_result = fn {:ok, result} -> IO.puts "Handling result..." {:ok, _} -> IO.puts "This would be never run as previous will be matched beforehand." {:error} -> IO.puts "An error has occurred!" end |
名前付き関数 | モジュールを定義し、その中に関数を作る | defmodule Greeter do def hello(name) do "Hello, " <> name end end |
関数本体が1行で済むなら、 do: を使ってより短くすることが出来る | defmodule Greeter do def hello(name), do: "Hello, " <> name end |