書籍『すごいErlangゆかいに学ぼう!/Learn You Some Erlang for great good! 』まとめ
第3章 関数の構文
3.1 パターンマッチ
function(Args) if X then 〔式〕 else if Y then 〔式〕 else〔式〕
ではなく
function(X) -> 〔式〕; function(Y) -> 〔式〕; function(_) -> 〔式〕.
と書く
- それぞれの function 宣言が 関数節
- 関数節は
;
で区切られ、 関数宣言 でまとめられる。
ちょっと凝ったパターンマッチ
-module(functions). -compile(export_all). % Replace with -export() later, for sanity's sake! head([H|_]) -> H. second([_,X|_]) -> X.
1> c(functions). {ok, functions} 2> functions:head([1,2,3,4]). 1 3> functions:second([1,2,3,4]). 2
束縛する変数
- 束縛されている変数に値を与えようとすると、新しい値が束縛されている値と同じでない限り 、エラーが発生します。
valid_time({Date = {Y,M,D}, Time = {H,Min,S}}) -> io:format("The Date tuple (~p) says today is: ~p/~p/~p,~n",[Date,Y,M,D]), io:format("The time tuple (~p) indicates: ~p:~p:~p.~n", [Time,H,Min,S]); valid_time(_) -> io:format("Stop feeding me wrong data!~n").
4> c(functions). {ok, functions} 5> functions:valid_time({{2013,12,12},{09,04,43}}). The Date tuple ({2013,9,6}) says today is: 2013/9/6, The time tuple ({9,4,43}) indicates: 9:4:43. ok 6> functions:valid_time({{2013,09,06},{09,04}}). Stop feeding me wrong data! ok
- この関数は、タプルが{{A,B,C},{D,E,F}}の形をしている限り、値として文字列でもアトムでもなんでも受け付けてしまう
3.2 ガードだ、ガード!
- ガードは、パターンマッチの表現力を高めるために 関数のヘッドに書ける追加の節
old_enough(X) when X >= 16 -> true; old_enough(_) -> false.
- ガード式の基本的なルールは、成功時に true を返さなければいけない
- もし false を返すか、例外を投げるなら、ガードは失敗
複数条件の場合
right_age(X) when X >= 16, X =< 104 -> true; right_age(_) -> false.
カンマ(,)は andalso 演算子と同じように振 る舞い、セミコロン(;)は orelse のように振る舞う
wrong_age(X) when X < 16; X > 104 -> true; wrong_age(_) -> false.
3.3 If ってなんだ?!
- if 節はガードのように振る舞い、ガードと同じような構文
- 関数節の先頭の外側で使う
- if節はガードパターンと呼ばれている
- 他の言語で見てきた if とは異なる
-module(what_the_if). -export([heh_fine/0]). heh_fine() -> if 1 =:= 1 -> works end, if 1 =:= 2; 1 =:= 1 -> works end, if1 =:= 2, 1 =:= 1 -> fails end.
1> c(what_the_if). ./what_the_if.erl:12: Warning: no clause will ever match ./what_the_if.erl:12: Warning: the guard for this clause evaluates to 'false' {ok,what_the_if} 2> what_the_if:heh_fine(). ** exception error: no true branch found when evaluating an if expression in function what_the_if:heh_fine/0
oh_god(N) -> if N =:= 2 -> might_succeed; true -> always_does %% This is Erlang's if's 'else!' end.
3> c(what_the_if). ./what_the_if.erl:12: Warning: no clause will ever match ./what_the_if.erl:12: Warning: the guard for this clause evaluates to 'false' {ok,what_the_if} 4> what_the_if:oh_god(2). might_succeed 5> what_the_if:oh_god(3). always_does
わかりやすく置き換える例
これを
if X > Y -> a() ; true -> b() end if X > Y -> a() ; X < Y -> b() ; true -> c() end
こう置き換える
if X > Y -> a() ; X =< Y -> b() end if X > Y -> a() ; X < Y -> b() ; X == Y -> c() end
3.4 もしも...の場合(In Case ... of)
- if式がガードのようなものだとしたら、case ... of式は関数のヘッド全体のようなもの
insert(X,[]) -> [X]; insert(X,Set) -> case lists:member(X,Set) of true -> Set; false -> [X|Set] end.
beach(Temperature) -> case Temperature of {celsius, N} when N >= 20, N =< 45 -> 'favorable'; {kelvin, N} when N >= 293, N =< 318 -> 'scientifically favorable'; {fahrenheit, N} when N >= 68, N =< 113 -> 'favorable in the US'; _ -> 'avoid beach' end.
beachf({celsius, N}) when N >= 20, N =< 45 -> 'favorable'; ... beachf(_) ->
3.5 どれを使えばいいの?
- if、case... of、関数という3つのうち、どれを使う かは、わりと答えるのが難しい質問
- 明らかな違いの 1 つは、1 つ以上の引数 が評価される時
- function(A,B) -> ...はAとBに対してガードと値のパターンマッチを持てる
- case 式では
case {A,B} of 〔パターン〕〔ガード〕-> ... end.