(2024-04-06更新)
Erlangについての自分用のメモです。
目次:
- 参考ページ
- プロセス
- dict:append/3 と dict:store/3 の違い
- 数値を2進数8桁右寄せで足りない桁を0で表示する
- 数値を書式指定で文字列に変換するには io_lib:format の結果に lists:flatten を使う
- BIF のソースは bif.c
- wxErlang
- Emacs erlang-mode
参考ページ
プロセス
プロセスの基本
プロセスはspawn
で作成する。
spawn(モジュール, 関数, 引数)
で指定したモジュールの指定した関数を新しいプロセスで実行する。
戻り値はPid。
spawn(?MODULE, start, [])
のように指定する。
spawn(fun() -> ... end)
のように無名関数を作成して実行することもできる。
リンク
メインプロセスから spawn
したプロセスは link
することで同時に終了させることができる。
Pid = spawn(spawn_test, say_something, [hello, 3]), link(Pid).
spawn_link/3
を使うとspawn
とlink
を一度に行なうことができる。
unlink/1
でリンクを解除する。リンクはスタックできないため、何度link
しても1回のunlink
で解除できる。
リンクしたプロセスが終了する時は終了シグナルを送ってくる。 終了シグナルは双方向で、どちらのプロセスが終了しても相手側に送られる。
process_flag(trap_exit, true)
をするとプロセスが終了シグナルで連鎖終了しなくなり、受け取った終了シグナルをメッセージに変換することができる。
受け取るメッセージ:
{'EXIT', Pid, normal}
- 通常終了、exit(normal)
で終了した場合{'EXIT', Pid, Reason}
-exit(Reason)
で終了した場合 (Reasonは文字列でもよい){'EXIT', Pid, killed}
-exit(Pid, kill)
で終了した場合
自分で exit(self(), kill)
した場合にはメッセージは送られずプロセスが終了し、連鎖的にリンクされたプロセスも終了する。
モニター
モニターは以下の特徴を持つ特殊なリンクと考えることができる。
- 一方向である
- スタックできる
リンクと違って連鎖的にプロセスが終了することはない。 そのため、他プロセスの監視に使うことができる。
Pid = spawn(spawn_test, say_something, [hello, 3]), Ref = monitor(process, Pid).
spawn_monitor/3
を使うとspawn
とmonitor
を一度に行なうことができる。
プロセスが終了した時には{'DOWN', Ref, process, Pid, Reason}
のようなメッセージが送られてくる。
demonitor(Ref)
でリンクを解除する。
demonitor(Ref, [flush, info])
のようにオプションを付けることができ、flush
はメールボックスのDOWN
メッセージを削除し、info
はモニターが存在したかどうかを真偽値で返す。
プロセスに名前をつける
register/2
でプロセスに名前をつける。
名前はアトムで指定する。
Pid = spawn(spawn_test, say_something, ["hello", 3]), register(hello, Pid).
名前のついたプロセスは whereis/1
で pid を得ることができる。
Pid = whereis(hello).
また、名前そのものをメッセージの送信先として使うことができる。
hello ! {self(), "world"}.
unregister/1
で名前を削除できる。
unregister(hello).
登録された名前は registered/0
で取得することができる。
1> registered(). [logger_sup,rex,user,erts_code_purger,kernel_safe_sup,init, erl_signal_server,logger_proxy,global_name_server, kernel_sup,inet_db,standard_error_sup,standard_error, logger_handler_watcher,file_server_2,kernel_refc, erl_prim_loader,global_group_check,logger_std_h_default, logger,code_server,global_group,socket_registry, application_controller]
dict:append/3
と dict:store/3
の違い
dict:append/3
を使うと値が配列で保存される。
これは同じキーの複数の値を格納することを想定しているからである。
1> D = dict:append(key, value, dict:new()). {dict,1,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}, {{[],[],[],[],[],[],[],[],[], [[key,value]], [],[],[],[],[],[]}}} 2> dict:find(key, D). {ok,[value]}
dict:store/3
を使うと値がそのまま保存される。
1> D = dict:store(key, value, dict:new()). {dict,1,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}, {{[],[],[],[],[],[],[],[],[], [[key|value]], [],[],[],[],[],[]}}} 2> dict:find(key, D). {ok,value}
数値を2進数8桁右寄せで足りない桁を0で表示する
画面に表示するには io:format/2
、io:fwrite/2
を使う。
文字列に変換するには io_lib:format/2
、io_lib:fwrite/2
を使う。
以下ではわかりやすくするため io_lib:format/2
を使い段階的に書式を追加する。
% 16進数の18を2進数で表示する 1> io_lib:format("~.2B", [16#18]). "11000" % 16進数の18を2進数桁8桁右寄せで足りない桁は空白で表示する 2> io_lib:format("~8.2B", [16#18]). " 11000" % 16進数の18を2進数桁8桁右寄せで足りない桁を#で埋めて表示する 3> io_lib:format("~8.2.#B", [16#18]). "###11000" % 16進数の18を2進数桁8桁右寄せで足りない桁を0で埋めて表示する 4> io_lib:format("~8.2.0B", [16#18]). "00011000"
数値を書式指定で文字列に変換するには io_lib:format
の結果に lists:flatten
を使う
io_lib:format
は内容によって結果がネストしたリストで返ってくるため文字列にするには lists:flatten
を使う。
1> io_lib:format("~p~c",[65,65]). ["65",65] 2> lists:flatten(io_lib:format("~p~c",[65,65])). "65A"
BIF のソースは bif.c
BIF (built-in functions) のソースは GitHub の bif.c です。
wxErlang
wxWidgets 自体の情報も載せる。
参考資料
- Erlang -- wxErlang Reference Manual
- 公式
- otp/lib/wx/examples at master · GitHub erlang/otp
- wxErlang - Getting Started (pdf)
- カウントダウンタイマーを作る入門記事
- [erlang-questions] wxErlang question 6 - Image display
- コールバック関数にオブジェクトを渡すうまい方法が紹介されている
get_env()
, set_env()
Erlangでは他のプロセスの変数にアクセスできないため、wxErlangの描画イベント時にエラーが発生することがある。
この場合にはメインプロセスから get_env()
で取得したものを set_env(Env)
でセットすればよい。
wxBitmap と wxImage の違い
- wxBitmap - プラットフォーム依存で DC への描画が簡単・高速
- wxImage - プラットフォーム中立で RGB + アルファ (透明度) のついたバッファでサイズやスケール変更、クリッピングなどができる
wxBitmap と wxImage は相互に変換が可能。
wxBitmap | wxImage | |
---|---|---|
特徴 | プラットフォーム依存 | プラットフォーム独立 |
それ自体への描画 | wxMemoryDC 経由で自由に描画 | setRGB でピクセル、四角形を描く。getData/setData でデータ列を直接操作可能 |
画面への描画 | wxDC:drawBitmap, wxDC:blit | 不可 |
参照: wxWidgets: wxBitmap Class Reference
wxPen と wxBrush
- wxPen - 図形の輪郭スタイルを表す
- wxBrush - 図形の塗り潰しスタイルを表す
wxPen を透明にするには style に ?wxTRANSPARENT を設定する。
% 輪郭を透明にする (描かない) wxDC:setPen(DC, wxPen:new(?wxBLACK, [{style, ?wxTRANSPARENT}])). % 白で塗り潰す wxDC:setBrush(DC, wxBrush:new(?wxWHITE)).
Emacs erlang-mode
Erlang -- Erlang mode for Emacs - 公式ドキュメント
~/.emacsか~/.emacs.d/init.elに以下のように記入する。 (パスはArch Linuxの例)
(setq load-path (cons "/usr/lib/erlang/lib/tools-3.2.1/emacs/" load-path)) (setq erlang-root-dir "/usr/lib/erlang/lib/") (setq exec-path (cons "/usr/lib/erlang/bin/" exec-path)) (require 'erlang-start)
erlang.elでインデントにスペースを使うようにする - YAMAGUCHI::weblog
インデントをタブではなくスペースにするには以下を追加する。
(add-hook 'erlang-mode-hook '(lambda() (setq indent-tabs-mode nil)))
代表的な操作:
- コードは自動的にインデントされる。インデントが間違っていたら
TAB
で調整 - 選択範囲を
C-c C-c
でコメントアウト、C-c C-u
でコメントを外す- 現在行ではなく選択範囲に対して行われるので注意すること
- コードを書いたら
C-c C-k
でコンパイル - Erlang shellバッファが開くので操作する
- Erlang shellバッファを閉じるには
init:stop().
を入力してからC-x kでバッファを削除
※Emacsについては GNU Emacsについてのメモ - はとのーと にまとめました。