書籍『すごい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.