Erlang/OTP チートシート

この記事は英語の原文を日本語に翻訳したものです。原文: https://adoptingerlang.org/docs/cheat_sheets/

翻訳元: adoptingerlang/adoptingerlang 2025-12-18(コミット 899008f

この節には、Erlangの基本的なデータ、型、構文についてあまり詳しくない場合に記憶を呼び起こすための、さまざまな備忘録が載っています。

データ型

名前説明Dialyzer構文の例
integer小数点を持たない数値integer(), pos_integer(), non_neg_integer()1, 2, 3, -213, 16#01FF, 2#101011
float小数点を持つ数値float()1.0, -1.0, 123.12, 1.0e232
numberfloatまたはintegerのどちらかnumber()1.0, 1
atom値そのものが名前になるリテラル・定数atom()abc, 'abc', some_atom@erlang, 'atom with spaces'
booleanatomのtrueまたはfalseboolean()true, false
reference一意で不透明な値reference()make_ref()
fun無名関数fun(), fun((ArgType) -> RetType)fun(X) -> X end, fun F(0) -> []; F(N) -> [1 | F(N-1)] end
portファイルディスクリプタ用の不透明な型port()N/A
pidプロセス識別子pid()<0.213.0>
tuple既知の要素の集合をまとめたものtuple(), {A, B, C}{celsius, 42}, {a, b, c}, {ok, {X, Y}}
map項の辞書map(), #{KType => VType}, #{specific_key := VType}#{a => b, c => d}, Existing#{key := Updated}
nil空リスト[][]
list項のリストを表す再帰的な構造list(), [Type][a, b, c], [a | [b | [c | []]]], "a string is a list"
binaryフラットなバイト列binary()<<1,2,3,4>>, <<"a string can be a binary">>, <<X:Size/type, _Rest/binary>>

項の順序は次のとおりです。

number < atom < reference < fun < port < pid < tuple < map < nil < list < binary

モジュールと構文

%%% これはモジュールレベルのコメントです
%%% @doc このタグは公式のEDocドキュメントを含みます。
%%% 参照する人にとって便利な場合があります
%%% @end
%%% rebar3 edoc でドキュメントを生成します

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% モジュール属性から始めましょう %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% これは属性または関数固有のコメントです。
%% 属性は `-' で始まり、関数は文字で始まります。
%% このファイルは `sample.erl' として保存する必要があります
-module(sample).

%% 関数はName/Arityの形式で記述され、
%% `-export([...]).' モジュール属性を通してエクスポートする必要があります
-export([f/0, f/1]).
-export([x/0]).         % 複数のexport属性を持つこともできます

%% 別のモジュールから関数を「import」することもできますが、
%% わかりやすさのため(そして名前空間がないため)
%% 実際にそうする人はほとんどいません
-import(module, [y/0]).

%% .hrlファイルにはヘッダが含まれ、モジュール内に直接
%% importされます。
%% 以下はsrc/内のプライベートなヘッダファイル、または
%% 現在のアプリのinclude/内の公開ヘッダファイルをincludeします
-include("some_file.hrl").
%% 以下は別のアプリケーションのinclude/ファイルにある
%% 公開ヘッダファイルをincludeします
-include_lib("appname/include/some_file.hrl").

%% 実装するインタフェースを指定します
-behaviour(gen_server).

%% レコードを定義します(コンパイラが特別に扱うタプルです)
-record(struct, {key = default :: term(),
                 other_key     :: undefined | integer()}).

%% ただのCスタイルのマクロです
-define(VALUE, 42).        % このモジュール内の?VALUEは`42'になります
-define(SQUARE(X), (X*X)). % 関数マクロ
-define(DBG(Call),         % 凝ったデバッグマクロ: ?DBG(2 + 2)
        io:format("DBG: ~s (~p): ~p~n",
                  [??Call, {?MODULE, ?LINE}, Call])).

%% 条件分岐
-ifdef(MACRO_NAME).        % 逆は: -ifndef(MACRO_NAME).
-define(OTHER_MACRO, ok).
-else.                     % 他の選択肢: -elif(NAME).
-define(MACRO_NAME, ok).
-endif.

%% 型定義
-type my_type() :: number() | boolean().
-type my_container(T) :: {[T], [T], my_type(), mod:type()}
-export_type([my_type/0, my_container/1]).

%% カスタム属性も定義できます
-my_attribute(hello_there).
-author("Duke Erlington").

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% ここからはコードと関数のためのモジュールです %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% @doc atomを返す引数0個の関数
-spec f() -> term(). % 任意のspec
f() -> ok.

-spec f(number()) -> float().
f(N) -> N + 1.0.

%% 節を使ったパターンマッチング
x([]) -> [];  % リストの基底となる再帰節
x([_H|T] -> [x | T]. % リストの要素をatom `x' に置き換えます

%% @private 変数束縛のルール
same_list(X = [_|_], X) -> true;
same_list([], []) -> true;
same_list(_, _) -> false.

%% 言語の演算子
operators(X, Y) ->
    +X, -Y, % 単項演算子
    X + Y, X - Y, X * Y, X / Y,   % 任意の数値
    X div Y, X rem Y,             % 整数専用
    X band Y, X bor Y, X bxor Y,  % ビット演算子
    X bsl Y, X bsr L,             % ビットシフト
    not X,                        % 論理否定
    X andalso Y, X orelse Y,      % ショートサーキットの論理演算子
    X < Y, X > Y, X >= Y, X =< Y, % 比較
    X == Y, X /= Y,               % 等価(floatとintでも==)
    X =:= Y, X =/= Y,             % 厳密な等価(floatとintは=/=)
    X ++ Y, X -- Y,               % YをXに追加、XからYを削除
    X ! Y.                        % プロセスXにメッセージYを送信

%% ガードの使用。有効なガード式は
%% erlang.org/doc/reference_manual/expressions.html#guard-sequences を参照
comfortable({celsius, X}) when X >= 18, X =< 26 -> % AND節
    true;
comfortable({celsius, _}) ->
    false.

uncomfortable({celsius, X}) when X =< 18; X >= 26 -> % OR節
    true;
uncomfortable({celsius, _}) ->
    false.

%% 'andalso' と 'orelse' の違い
conds(X) when (is_number(X) orelse is_integer(X))
               andalso X < 9 ->
    %% (A AND B) OR C と等価
    true;
conds(X) when is_number(X); is_integer(X), X < 9 ->
    %% - , や ; では括弧が使えません
    %% - A OR (B AND C) と等価です
    true;
conds(T) when element(1, T) == celsius; is_integer(T) ->
    %% element/2はタプルから要素を取り出します。`T'がタプルで
    %% なければ呼び出しは失敗し、代わりに`is_integer/1'が
    %% 試されます
    true;
conds(T) when element(1, T) == celsius orelse is_integer(T) ->
    %% これは決して動きません。element/2が失敗すると
    %% `orelse'式全体が失敗し、`is_integer/1'はスキップされます
    true.

%% 条件分岐
conditional('if', Light) ->
    if Light == red -> stop;
       Light == green; Light == yellow -> go_fast;
       true -> burnout % else節です!
    end;
conditional('case', {Light, IsLate}) ->
    case Light of
        green -> go;
        yellow when IsLate -> go_fast;
        _ -> stop
    end;
conditional(pattern, green) -> go;
conditional(pattern, yellow) -> slow;
conditional(pattern, red) -> stop.

%% リスト内包表記とバイナリ内包表記
comp(ListA, ListB) ->
    [X*X || X <- ListA, X rem 2 == 0], % 偶数を2乗します
    [{X,Y} || X <- ListA, Y <- ListB], % すべての組み合わせ
    << <<X:8>> || X <- ListA >>.       % リストをバイト列に変換します
comp(BinA, BinB) -> % 今度はバイナリで
    << <<X*X:32>> || <<X:8>> <= Bin, X rem 2 == 0 >>,
    [{X,Y} || <<X:32>> <= BinA, <<Y:8>> <= BinB],
    [X || <<X:8>> <= BinA].

%% 無名関数と高階関数
higher_order() ->
    If = fun(Light) -> conditional('if', Light) end,
    Case = fun(Light) -> conditional('case', {Light, true}) end,
    lists:map(If, [green, yellow, red]),
    lists:map(Case, [green, yellow, red]),
    If(red), % 直接呼び出すこともできます
    lists:map(fun(X) -> X*X end, [1,2,3,4,5]).

try_catch() ->
    try
        some_call(),     % この呼び出しの例外も捕捉されます
        {ok, val},       % パターンマッチしたい一般的な正常値
        {error, reason}, % パターンマッチしたい一般的な異常値
        % これらの式はいずれも実行フローを中断させます
        throw(reason1), % ローカルでないreturn、内部例外
        error(reason2), % 修正不能なエラー
        exit(reason3)   % プロセスを終了させるべき場合
    of  % このセクションは任意です。ここでの例外は捕捉されません
        {ok, V} ->
            do_something(V),
            try_catch(); % スタックを溢れさせずに安全に再帰します
        {error, R} ->
            {error, R} % そのまま返します
    catch % このセクションは任意です。さまざまなパターンがあります
        throw:reason1 -> handled;
        reason2 -> oops; % `throw'は暗黙の型なので決してマッチしません
        error:reason2 -> handled;
        exit:reason3 -> handled;
        throw:_ -> wildcard_throws;
        E:R when is_error(E) -> any_error;
        _:_:S -> {stacktrace, S}; % スタックトレースを取り出します
    after -> % 任意の'finally'ブロックです
        finally
    end.

プロセスとシグナル

%% 新しいプロセスを開始します
Pid = spawn(fun() -> some_loop(Arg) end)
Pid = spawn('name@remote.host', fun() -> some_loop(Arg) end)
Pid = spawn(some_module, some_loop, [Arg])
Pid = spawn('name@remote.host', some_module, some_loop, [Arg])
%% リンクされたプロセスをspawnします
Pid = spawn_link(...) % spawn/1-4と同じく引数は1〜4個
%% 監視付きのプロセスを不可分にspawnします
{Pid, Ref} = spawn_monitor(fun() -> some_loop(Arg) end)
{Pid, Ref} = spawn_monitor(some_module, some_loop, [Arg])
%% 凝ったオプション付きでspawnします
spawn_opt(Fun, Opts)
spawn_opt(Node, Fun, Opts)
spawn_opt(Mod, Fun, Args, Opts)
spawn_opt(Node, Mod, Fun, Args, Opts)
%% オプションは次のspecに従う必要があります。多くは高度な用途向けです
[link | monitor |
 {priority, low | normal | high | max} |    % 触らないこと
 {fullsweep_after, integer() >= 0} |        % フルGC
 {min_heap_size, Words :: integer() >= 0} | % 性能チューニング
 {min_bin_heap_size, Words} |
 {max_heap_size,                    % これを超えるとプロセスが
   Words |                          % killされる可能性があるヒープサイズ。
   #{size => integer() >= 0,        % 最大キューサイズを間接的に
     kill => boolean(),             % 設定するのに使います
     error_logger => boolean()}}

%% プロセスにexitシグナルを送信します
exit(Pid, Reason)

%% メッセージを受信します
receive
    Pattern1 when OptionalGuard1 ->
        Expression1;
    Pattern2 when OptionalGuard2 ->
        Expression2
after Milliseconds -> % 任意
    Expression
end

%% プロセスに名前を付けます
true = register(atom_name, Pid)
true = unregister(atom_name)
Pid | undefined = whereis(atom_name)

%% 監視
Ref = erlang:monitor(process, Pid)
true = erlang:demonitor(Ref)
true | false = erlang:demonitor(Ref, [flush | info])

%% リンク
link(Pid)
unlink(Pid)
process_info(trap_exit, true | false)

リンクと監視のセマンティクスを図で示すと、次のようになります。

監視は一方向の情報伝達シグナルであり、積み重なります

捕捉されていないリンクは双方向であり、理由が’normal’でない限り相手のプロセスをkillします

捕捉されたリンクはメッセージに変換されます。ただし捕捉不能な’kill’という理由は例外です

OTPのプロセスは、supervisionのちょっとした仕掛けによりセマンティクスがわずかに異なります。

捕捉されていないリンクはOTPでも同様に動作します

捕捉されたリンクは、プロセスの親自身が終了する場合に特別な振る舞いをします

supervisorは終了理由によってログの出し方を変えます

ビヘイビア

ここにすべてのOTPビヘイビアが載っているわけではなく、もっとも頻繁に使われるものだけを挙げています。

アプリケーション

TriggerCalled ByHandled ByReturn説明
application:start/1-2client or booting VMstart(Type, Args){ok, pid()} | {ok, pid(), State}ルートのsupervisorを起動する必要があります
{start_phases, [{Phase, Args}]} in app filekernel booting the appstart_phase(Phase, Type, Args)ok | {error, Reason}任意。初期化の特定のステップを分離できます
application:stop/1app shutting downprep_stop(State)State任意。supervisorツリーがシャットダウンされる前に呼ばれます
application:stop/1app shutting downstop(State)term()アプリの実行が終わった後、後片付けのために一度呼ばれます
Hot code updateSASL’s release handlerconfig_change(Changed::[{K,V}], New::[{K,V}], Removed::[K])okVMのrelup機能を使ったホットコードアップデートの後、設定値が変更されていれば呼ばれます

supervisor

TriggerCalled ByHandled ByReturn説明
supervisor:start_link/2-3parent processinit(Arg)ignore | {ok, {SupFlag, [Child]}}supervisorを定義します。詳細は公式ドキュメントを参照してください

gen_server

TriggerCalled ByHandled ByReturn説明
gen_server:start_link/3-4supervisorinit(Arg){ok, State [, Option]} | ignore | {stop, Reason}プロセスの初期状態を設定します
gen_server:call/2-3clienthandle_call(Msg, From, State){Type::reply | noreply, State [, Option]} | {stop, Reason [, Reply], State}リクエスト/レスポンスのパターンです。メッセージを受信し、応答を返すことが期待されます
gen_server:cast/2clienthandle_cast(Msg, State){noreply, State [, Option]} | {stop, Reason, State}プロセスに送られる情報です。送りっぱなしで応答を待ちません
Pid ! Msgclienthandle_info(Msg, State)same as handle_cast/2帯域外のメッセージです。監視シグナルや、exitを捕捉している場合の’EXIT’メッセージを含みます
Setting an Option value to {continue, Val}the server itselfhandle_continue(Val, State)same as handle_cast/2長時間かかる処理を、内部で発火できるイベントに分割するために使います
gen_server:stop/1,3client or supervisorterminate(Reason, State)term()プロセスが自発的に、あるいはエラーによってシャットダウンするときに呼ばれます。プロセスがexitを捕捉していない場合、このコールバックは省略できます
sys:get_status/2-3, crash logsclient, the server itselfformat_status(normal | terminate, [PDict, State])[{data, [{"State", Term}]}]デバッグ呼び出しやエラーログに載る情報を追加・削除するために使います
N/Asupervisorcode_change(OldVsn, State, Extra){ok, NewState}リリースを使ったホットコードアップグレードの際、適切な指示が与えられていれば、状態を持つプロセスを更新するために呼ばれます

gen_statem

プロセス管理

TriggerCalled ByHandled ByReturn説明
gen_statem:start_link/3-4supervisorinit(Arg){ok, State, Data [, Actions]} | ignore | {stop, Reason}ステートマシンの初期状態とデータを設定します
N/Ainternalcallback_mode()[state_functions | handle_event_function [, state_enter]]FSMの種類と、状態への遷移時に特別な内部イベントを発火するかどうかを定義します
gen_statem:stop/1,3client or supervisorterminate(Reason, State, Data)term()プロセスが自発的に、あるいはエラーによってシャットダウンするときに呼ばれます。プロセスがexitを捕捉していない場合、このコールバックは省略できます
sys:get_status/2-3, crash logsclient, the server itselfformat_status(normal | terminate, [PDict, State, Data])[{data, [{"State", Term}]}]デバッグ呼び出しやエラーログに載る情報を追加・削除するために使います
N/Asupervisorcode_change(OldVsn, State, Data, Extra){ok, NewState, NewData}リリースを使ったホットコードアップグレードの際、適切な指示が与えられていれば、状態を持つプロセスを更新するために呼ばれます

状態の処理と遷移

callback_mode()の値に応じて、handle_event/4またはStateName/3のいずれかの関数で処理されます。関数のシグネチャは次のいずれかです。

  • handle_event(EventType, EventDetails, State, Data)
  • State(EventType, EventDetails, Data)

callback_mode()state_functionsを定義していても、Stateの値がリストでなければhandle_event/4が呼ばれます。どちらの関数についても、返り値としてありうるのは次のいずれかです。

  • {next_state, State, Data}
  • {next_state, State, Data, [Actions, ...]}
  • {stop, Reason, Data}
  • {stop, Reason, Data, [Actions, ...]}

keep_state_and_data{keep_state, Data}{repeat_state, Data}など、さまざまな短縮形が存在します。その内容についてはドキュメントを参照してください。

Actionsの値は、次のリスト(すべてではありません)の任意の組み合わせです。postpone{next_event, EventType, EventDetails}hibernate{timeout, Delay, EventDetails}{state_timeout, Delay, EventDetails}{reply, From, Reply}hibernate。その他のオプションについてはドキュメントを参照してください。

TriggerCalled ByEvent TypeEvent Details説明
gen_statem:call/2-3client{call, From}term()リクエスト/レスポンスのパターンです。メッセージを受信し、応答を返すことが期待されます
gen_statem:cast/2clientcastterm()プロセスに情報を送る必要があります。送りっぱなしで応答を待ちません
Pid ! MsgclientinfoMsg帯域外のメッセージです。監視メッセージや、捕捉された’EXIT’シグナルを含みます
{timeout, T, Msg}Action return valuetimeoutMsgステートマシンがTミリ秒の間新しいイベントを受信しなかったときに、内部で設定・受信できる特定のタイムアウトです
{state_timeout, T, Msg}Action return valuestate_timeoutMsgステートマシンがTミリ秒の間別の新しい状態に遷移しなかったときに、内部で設定・受信できる特定のタイムアウトです
{next_event, internal, Msg}Action return valueinternalMsg外部からの呼び出しに見せずに自分自身を発火させたいステートマシンが生成できる内部メッセージです