3章あたり。
Erlangの簡単な逐次的なコードやパターン照合に関する考え方を関数定義で使う方法を学ぶ
- funの引数は何個でもよい
- 引数の個数を間違っているとエラーになる
1> Double = fun(X) -> 2 * X end.
#Fun<erl_eval.6.118419387>
2> Double(2).
4
3> TempConvert = fun({c,C}) -> {f, 32 + C*9/5};
3> ({f,F}) -> {c, (F-32)*5/9}
3> end.
#Fun<erl_eval.6.118419387>
4> TempConvert({c,100}).
{f,212.0}
5> TempConvert({f,212}).
{c,100.0}
- リストLの各要素を関数Fの引数に適用して得られたリストを返す
1> L = [1,2,3,4].
[1,2,3,4]
2> Double = fun(X) -> 2 * X end.
#Fun<erl_eval.6.118419387>
3> lists:map(Double, L).
[2,4,6,8]
- リストLの要素EのうちP(E)がtrue になるものだけから新しいリストを返す。
1> Even = fun(X) -> (X rem 2) =:= 0 end.
#Fun<erl_eval.6.118419387>
2> lists:filter(Even, [1,2,3,4,5,6,8]).
[2,4,6,8]
・lib_misc.erl
for(Max, Max, F) -> [F(Max)];
for(I, Max, F) -> [F(I)|for(I+1, Max, F)].
・Eshell
1> lib_misc:for(1,10,fun(I) -> I end).
[1,2,3,4,5,6,7,8,9,10]
・lib_misc.erl
sum([H|T]) -> H + sum(T);
sum([]) -> 0.
1> L = [1, 2, 3, 4, 5].
[1,2,3,4,5]
2> [X * 2 || X <- L].
[2,4,6,8,10]
%% リスト内包表記のジェネレータ部はフィルタと同様に機能する
1> [ X || {a, X} <- [{a,1},{b,2},{c,3},{a,4},hello,"wow"]].
[1,4]
・lib_misc.erl
qsort([]) -> [];
qsort([Pivot|T]) ->
qsort([X || X <- T, X < Pivot])
++ [Pivot] ++
qsort([X || X <- T, X >= Pivot]).
%% ++ はリストを結合する中置演算子
・Eshell
1> L=[23,6,2,9,27,400,78,45,61,82,14].
[23,6,2,9,27,400,78,45,61,82,14]
2> lib_misc:qsort(L).
[2,6,9,14,23,27,45,61,78,82,400]
- パターン照合の威力をさらに高めるための機構
- ガードを関数定義のヘッドで使う場合はwhenキーワードで始める
- 式が使えるとこなら、どこでもガードを使うことができる
- ガードは一連のガード式をカンマ(,)で区切れる
max(X, Y) when X > Y -> X;
max(X, Y) -> Y.
f(X,Y) when is_integer(X), X > Y, Y < 6 -> ...
- レコードはタプルの特定要素に名前を付けることができる
- Nameはレコード名
- key1,key2などはアトムでなればならない
- レコードの各フィールドにはデフォルト値を指定できる
- レコードの定義は2パターンで行える
- Erlangのソースファイルに定義
- 複数のモジュール間でrecord定義を利用できない
- hrl拡張子のファイルに定義
- 複数のモジュール間でrecord定義を利用できる
- rr(read records)でレコード定義を読み込む
- Erlangのソースファイルに定義
-record(Name, {
%% 以下の2 つのキーにはデフォルト値がある
key1 = Default1,
key2 = Default2,
...
%% 下記の行はkey3 = undefined と同じ
key3,
...
}).
- 新しいレコードを作成するには、#todo{key1=Val, ..., keyN=ValN}という構文を使う
- 作成時、キーをを省略した場合はレコードの定義で指定されているデフォルト値が使われる
- 作成するレコードは元のレコードのコピーであって元のレコードは変化しない
- 取り出し方法には2パターンがある
- パターン照合
- ドット構文
%% レコード定義をインクルード
1> rr("records.hrl").
[todo]
%% 参照
2> X=#todo{}.
#todo{status = reminder,who = joe,text = undefined}
%% 作成
3> X1 = #todo{status=ugent, text="book"}.
#todo{status = ugent,who = joe,text = "book"}
%% パターン照合で取り出し
4> #todo{who=W, text=Txt} = X1.
#todo{status = ugent,who = joe,text = "book"}
5> W.
joe
6> Txt.
"book"
%% ドット構文で取り出し
7> X1#todo.who.
joe
8> X1#todo.text.
"book"
%% case式
case Expression of
Pattern1 [when Guard1] -> Expr_seq1;
Pattern2 [when Guard2] -> Expr_seq2;
...
PatternN [when GuardN] -> Expr_seqN
end
%% if
if
Guard1 ->
Expr_seq1;
Guard2 ->
Expr_seq2;
...
GuardN ->
Expr_seqN
end
- 1つの関数で2つのリストを効率良く得る
奇数と偶数を分ける ・lib_misc.erl
odds_and_events_acc(L) -> odds_and_events_acc(L, [], []).
odds_and_events_acc([H|T], Odds, Evens) ->
case (H rem 2) of
1 -> odds_and_events_acc(T, [H|Odds], Evens);
0 -> odds_and_events_acc(T, Odds, Evens)
end;
odds_and_events_acc([], Odds, Evens) -> {Odds, Events}.
・Eshell
1> lib_misc:odds_and_events_acc([1,2,3,4,5,6]).
{[5,3,1],[6,4,2]}