/ での除算結果は、割りきれても必ず浮動小数点に変換される。
初めから浮動小数点の演算をしてるのかな?
1> 4/2. 2.0 2> 4 div 2. 2
アトム
小文字から始まる式は、全てアトムになる。
1> hello. hello 2> Hello. * 1: variable 'Hello' is unbound 3> hello=hello. hello 4> Hello=hello. hello 5> Hello. hello
無名変数
「_」 は、何度でも代入している、不要な値を切り捨てるために使う変数。
1> Person={person,{name,calmoka},{age,36}}. {person,{name,calmoka},{age,36}} 2> {_,{name,Name},_}=Person. {person,{name,calmoka},{age,36}} 3> Name. calmoka
文字列は整数のリスト
1> [99,97,116]. "cat" 2> [H|T]="cat". "cat" 3> H. 99 4> T. "at"
f() 変数の束縛状態を全て解除
1> X=123. 123 2> f(). ok 3> X=234. 234
リスト内包表記
リスト L から、Xを取り出して、F(X)した結果のリストを作成する。
[F(X) || X <- L]. 1> [X * 2 || X <- [1,2,3,4,5]]. [2,4,6,8,10]
ガード
ガード列、G1;G2;G3...;Gn がtrueになるのは、ガード G1 ~ Gn の少なくともいずれか1つがtrueになる場合。
ガードは一覧のガード式を「,」で区切ったもの。
GuardExpr1, GuardExpr2, ..,GuardExprn がtrueになるのは、全てのガード式が true の場合。
and, andalso, or, orelse
and, or は全ての式を評価する。
andalso, orelse は評価がわかった時点で結果を出す。
f(X) = when (X == 0) or (1/X > 2) ... g(X) = when (X == 0) orelse (1/X > 2) ...X = 0 の時、f(X) は一致しない。
ガードで使えるBIF 例
is_atom(X) is_binary(X) is_constant(X) is_float(X) is_function(X) is_function(X, N) // 引数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) // TagのレコードでNサイズ abs(X) element(N, X) // タプルXのN番目の要素 float(X) hd(X) // リストXのヘッド length(X) node() // 現在のノード node(X) // X(プロセス、リファレンス、ポート)が作られたノード round(X) // 整数に四捨五入 self() // 現在のプロセスのPID size(X) trunc(X) // Xを整数に切り捨てる tl(X) // リストXのテールhttp://erldocs.com/R14B01/erts/erlang.html?i=0&search=erlang#undefined
レコードの定義
key=hoge とすると、hogeが初期値になる。
-record(rec, { key1=default, key2, key3 }). % レコード定義は .hrl ファイル内で。 1> rr("record.hrl"). rec 2> X = #rec{key2=key2}. #rec{key1 = default,key2 = key2,key3 = undefined} % rf() で、レコード定義をクリア、各変数はタプルになる。 3> rf(rec). ok 4> X. {rec,default,key2,undefined}
case文 で filter を書くと
filter(P, [H|T]) -> case P(H) of true -> [H|filter(P, T)]; false -> filter(P, T) end; filter(P, []) -> []. case Expression of Pattern1 [When Guard1] -> Expr_seq1; Pattern2 [When Guard2] -> Expr_seq2 end % ついでにif文 if Guard1 -> Expr_seq1; Guard2 -> Expr_seq2; true -> Expr_seq3 end
リストは必ずヘッドに追加する
その方が効率がいいらしい。
並び順は逆になるがその場合最後に、lists:reverse/1 を呼び出す。
List ++ [H] は悪らしい。
アキュムレータ
一時的に保存する領域を使って関数を作る。
[H || filter(H)] よりも空間効率がいいらしい。
整数のリストを偶数と奇数のリストに分けるサンプル。
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, Odds, [H|Evens]); 0 -> odds_and_evens(T, [H|Odds], Evens) end; odds_and_evens([], Odds, Evens) -> {lists:reverse(Odds), lists:reverse(Evens)}. 1> lib_misc:odds_and_evens([1,2,4,5,6,7,8,89,3]). {[2,4,6,8],[1,5,7,89,3]}
例外、エラー
exit(Why) - プロセスを終了したい場合 throw(Why) - 呼び出し側が補足する可能性がある例外 erlang:error(Why) - クラッシュエラー 内部的に発生したエラーと同等
try catch のスタイル
エラーが起こることが多い場合は、try catch を使わずに戻り値で処理する。
case f(X) of {ok, Val} -> ...; {error, Why} -> ... end,
関数内で throw(Why) する場合は、
try f(X) of Val -> ...R catch throw:{ExceptionA, Reason} -> ...; throw:{ExceptionB, Reason} -> ...; _:_ -> ...; exit:Ex -> ...; error:Ex -> ... end通常は、exit は補足しないほうがイイ?
また、_:_, _ で補足できるのは、throw だけ。
ビット構文: 24ビットカラーのパック、アンパック
1> R = 16#ff. 255 2> G = 16#66. 102 3> B = 16#00. 0 4> RGB = <<R:8, G:8, B:8>>. <<255,102,0>> 5> <<R1:8, G1:8, B1:8>> = RGB. <<255,102,0>> 6> R1. 255 7> G1. 102 8> B1. 0
アンダースコア変数
_ で始まる変数は、一度しか使われなくても警告が出ない。
そのため、「_」の代わりに切り捨てるデータに使うことが可能。
クラッシュダンプ
webtool で解析。
webtool:start().
プロセス タイムアウト付きの受信
receive Pattern1 [when Guard1] -> Expression1; Pattern2 [when Guard2] -> Expression2 ... after Time -> Expression end.
on_exitハンドラ
プロセスが終了するときになにか処理をしたい場合は、
on_exit(Pid, F) を使う。
プロセスの終了時の処理
気にしないパターン
spawn(fun() -> ... end)自分も死ぬ
spawn_link(fun() -> ... end)死んだことを知りたい
process_flag(trap_exit, true), spawn_link(fun() -> ... end) loop() -> receive {'EXIT', Pid, Reason} -> ... end
関数を全てexportする
-compile(export_all).
パスの追加
パスの先頭に追加 $ erl -pa Dir1 -pa Dir2 > code:add_patha(Dir) パスの末尾に追加 $ erl -pz Dir1 -pz Dir2 > code:add_pathz(Dir)
file_info のレコードファイル
-include_lib("kernel/include/file.hrl").
分散ノードの起動
クライアントとサーバが1つのホストで別ノード
-sname でショートネームを利用する設定にしてerlを起動
erl -sname node1 (node1@localhost)1> xxx:start(). ok (node1@localhost)2> rpc:call(node2@localhost, M, F, A).クライアントとサーバが別ホスト
-name -setcookie クッキーで同じクラスタに設定。
erl -name node1 -cookie somecookie (node1@host1)1> xxx:start(). ok (node1@host1)2> rpc:call(node2@host2.example.com, M, F, A).
Erlangで使いポートを設定して起動
elr -name ... -setcookie ... -kernel inet_dist_listen_min Min inet_dist_listen_max Max
インターネット上の別ホストで分散させる場合に開けておくポート
4369 の TCP/UDP epmd(Erlang Port Mapper Daemon)が利用する。
別ホストでプロセスを起動
spawn に Node名をつけて起動するだけ。他の関数も同様に第一引数がNodeになる。
spawn('somenode@somehost.example.com', Mod, Fun, Args).
別ホストで関数を実行
rpcモジュールの関数群を利用。
rpc:call(Node, Mod, Fun, Args). など
フォーマットした文字列を取得
Str = lists:flatten(io_lib:format("foo ~p ~p", [bar, hoge])).
Dialyzer
PLTファイルを生成して、beamファイルかerlファイルを指定して解析する。
dialyzer --build_plt --apps erts kernel stdlib crypto compiler hipe dialyzer -Wunmatched_returns -Werror_handling -Wrace_conditions ... -c hoge.erl
参考本
No comments:
Post a Comment