Programming Erlang読書ノート3:Sequential Programming


moduleはErlangコードの基本ユニットで、私たちが書いたすべてのfunctionはmoduleに保存され、moduleは保存されています.Erlファイルの中
moduleコンパイルbeamファイルの後方で実行可能
Erlang_HOMEは.Erlangのファイル:

io:format("consulting .erlang in ~p~n", [element(2, file:get_cwd())]).
%% Edit to the directory where you store your code
c:cd("C:/Program Files/erl5.6/work").
io:format("Now in:~p~n", [element(2, file:get_cwd())]).

このようにErlangが持参したWindowsプログラムを起動すると自動的にworkディレクトリに切り替わります
funsは匿名の方法です.

1> Z = fun(X) -> 2*X end.
2> TempConvert = fun({c, C}) -> {f, 32 + C*9/5};
                    ({f, F}) -> {c, (F-32)*5/9}
                 end.

funsを返す方法とfunsをパラメータとして受け入れる方法をhigher-order方法と呼ぶ
funsをパラメータとして受け入れる方法:

1> L = [1,2,3,4].
[1,2,3,4]
2> lists:map(Double, L).
[2,4,6,8]
3> lists:filter(Even, L).
[2,4]

funsを返す方法:

1>Fruit = [apple, pear, orange].
[apple, pear, orange]
2> MakeTest = fun(L) -> (fun(X) -> lists:member(X, L) end) end.
#Fun<erl_eval.6.56006484>
3> IsFruit = MakeTest(Fruit).
#Fun<erl_eval.6.56006484>
4> IsFruit(pear).
true
5> IsFruit(dog).
false
6> lists:fitler(IsFruit, [dog, orange, cat, apple, bear]).
[orange, apple]

Erlangにはforループはありませんが、私たちは自分で定義することができます.

for(Max, Max, F) -> [F(Max)];
for(I, Max, F) -> [F(I)|for(I+1, Max, F)].

1> lib_misc:for(1,10,fun(I) -> I end).
[1,2,3,4,5,6,7,8,9,10]

moduleは、このmodule名を宣言するために使用されます.
Excortは、本moduleの公開方法をエクスポートするために使用されます.
import他のmoduleをインポートするための公開方法
List Comprehension([F(X)‖X<−L])を使用して、プログラミングを簡略化し、可読性を高める:

1> L = [1,2,3,4,5].
[1,2,3,4,5]
2> lists:map(fun(X) -> 2*X end, L).
[2,4,6,8,10]
3>[2*X || X <- L].
[2,4,6,8,10]

List ComprehensionでQuicksortを実現する:

qsort([]) -> [];
qsort([Pivot|T]) ->
    qsort([X || X <- T, X < Pivot]) ++ [Pivot] ++ qsort([X || X <- T, X >= Pivot]).

List ComprehensionでPythagorean Tripletsを実現する:

pythag(N) ->
    [ {A,B,C} ||
        A <- lists:seq(1,N),
        B <- lists:seq(1,N),
        C <- lists:seq(1,N),
        A+B+C =< N,
        A*A+B*B =:= C*C
    ].

算数式

Op           Argument Type Priority
+X               Number       1
-X               Number       1
X*Y              Number       2
X/Y              Number       2
bnot X           Integer      2
X div Y          Integer      2
X rem Y          Integer      2
X band Y         Integer      2
X+Y              Number       3
X-Y              Number       3
X bor Y          Integer      3
X bxor Y         Integer      3
X bsl N          Integer      3
X bsr N          Integer      3

優先度が1の場合は先に実行し、次に2,and soon
かっこで優先度を変更できます.
左から右へ同じ優先順位で実行
GuardはErlangの式で、キーワードはwhenです.

max(X, Y) when X > Y -> X;
max(X, Y) -> Y.

Guard Sequenceは1つまたは複数のGuardで、";"ぶんかつ
G1;G2;...;Gnのうち少なくとも1つのGuardがtrueであればこのGuard Sequenceがtrueとなる
Guardは、「,」で区切られた1つ以上のGuard式です.
GuardExpr1,GuardExpr2,...,GuardExprNのすべてのGuard式がtrueの場合true
正当なGuard式:
1,The atom true
2,Other constants(terms and bound variables),all evaluate to false
3,Calls to the guard predicates and to the BIFs
4,Term comparisons
5, Arithmetic expressions
6, Boolean expressions
7, Short-circuit boolean expressions
Guard predicates:

is_atom(X)
is_binary(X)
is_constant(X)
is_float(X)
is_function(X)
is_function(X, N)
is_integer(X)
is_list(X)
is_number(X)
is_pid(X)
is_port(X)
is_reference(X)
is_tuple(X)
is_record(X, Tag)
is_record(X, Tag, N)

Guard trueはif式のcatch allに使用されます.

if
    Guard -> Expressions;
    Guard -> Expressions;
    ...
    true -> Expressions
end

Guard buit-in functions:

abs(X)
element(N, X)
float(X)
hd(X)
length(X)
node()
node(X)
round(X)
self()
size(X)
trunc(X)
tl(X)

RecordはTupleの要素に名前を付けるために使用されます.

-record(todo, {status=reminder, who=joe,text}).

レコードのfileにはデフォルト値があります
Recordの定義は、Erlangのソースコードまたは外部に置くことができる.hrlファイルにはErlangソースコードが導入されています
Eshellでrr()メソッドを使用してRecord定義を読み込むことができます.

1> rr("records.hrl").
[todo]

Recordの作成と変更:

2> X=#todo{}.
#todo{status = reminder, who = joe, text = undefined}
3> X1=#todo{status=urgent, text="Fix errata in book"}.
#todo{status = urgent, who = joe, text = "Fix errata in book"}
4> X2=X1#todo{status=done}.
#todo{status = done, who = joe, text = "Fix errata in book"}
5> #todo{who=W, text=Txt} = X2.
#todo{status = done, who = joe, text = "Fix errata in book"}
6> W.
joe
7> Txt.
"Fix errata in book"
8> X2#todo.text.
"Fix errata in book"

RecordはTupleの偽装です.

1> X.
#todo{status = done, who = joe, text = "Fix errata in book"}
2> rf(todo).
ok
3> X.
{todo, done, joe, "Fix errata in book"}

ケース式:

case Expression of
    Pattern1 [when Guard1] -> Expr_seq1;
    Pattern2 [when Guard2] -> Expr_seq2;
    ...
end

if式:

if
    Guard1 ->
        Expr_seq1;
    Guard2 ->
        Expr_seq2;
    ...
end

1つの整数リストをパリティで2つのリストに分けます.

odds_and_evens(L) ->
  odds_and_evens(L, [], []).

odds_and_evens([H|T], Odds, Evens) ->
  case (H rem 2) of
    1 -> odds_and_evens(T, [H|Odds], Evens);
    0 -> odds_and_evens(T, Odds, [H|Evens])
  end;
odds_and_evens([], Odds, Evens) ->
  {lists:reverse(Odds), lists:reverse(Evens)}.