[トップ][ノート][編集履歴][一覧][最近の更新][->English]

Erlang/2006/03/25/side-effect

Category of Erlang

Erlangと副作用

関数型言語であるErlangは副作用を起こす操作は一般の文法上には存在していない(代入もcall/ccも無い)が、 それでもそのような結果を引き起こすことは可能だ。

Erlangで副作用を発生させる手段には2種類ある(他にもあったらやんわりと指摘頂きたい)。

ドライバは外部のオブジェクト(CやJavaやその他実行ファイル)とリストをやりとりするものだから、 当然副作用は起こりうる(というより、この場合は副作用を起こすことが目的である)ので、ここでは説明しない。

workerとして振る舞わせるには、例えば、

 -behaviour(gen_server).

とプログラム中に書くことでgen_serverとして機能するようになる。

gen_serverとして書かれたコードは5つのコールバック関数を持ち、 supervisorから呼び出されるようになる。

Erlangでは、

 Pid = spawn(?MODULE, foo, []),
 Pid ! Message,
 ...

のようなコードを用いて、サーバ側の状態の変更をさせるのが一般的なのだが、 gen_serverでは、そうする必要が無くなる(単にコールバックをトリガしてやるだけでよい)。 その代償として、 その「状態」を管理することができなくなる(状態の変更はgen_serverとsupervisorの間で行なわれる)。 これが副作用に見えるわけだ。

例を挙げる。

-module(inc).
-behaviour(gen_server).

-export([start_link/0]).
-export([inc/0]).
-export([init/1, handle_call/3]).

start_link() ->
    gen_server:start_link({local, inc}, inc, [], []).

inc() ->
    gen_server:call(?MODULE, inc).

init(_Args) ->
    process_flag(trap_exit, true),
    {ok, 0}.

handle_call(inc, _From, State) ->
    Reply = State,
    {reply, Reply, State + 1}.

先ほど5つのコールバック関数と書いたが、 ここではinit/1とhandle_call/3のみ使用した。

start_link/0とinc/0が利用者側のコードで、 他の関数は触ることができないようになっている。 状態の変更はhandle_call/3で行なっている。

実行結果は以下のようになる。

1> inc:start_link().
{ok,<x.x.x>}
2> inc:inc().
0
3> inc:inc().
1
4> inc:inc().
2
blog comments powered by Disqus