Erlang Lite #4の予習をやってみた

んとなく時間ができたのでErlang Lite #4の予習やってみた.
とりあえずchap.4のexerciseを解いてみたのでそれだけ.
未だErlangよく分かってない上に英文読み違えてたりする可能性高しなのでつっこみよろしくお願いします!!

Ex.4-1
%% 
%% Exercise 4-1
%% An Echo Server
%%
%% 

-module(echo).
-export([start/0, print/1, stop/0, loop/0]).



%% 
%% echoサーバの起動
%% 
start() ->
    register(eserver, spawn(echo,loop,[])),
    io:format("echo server is running....~n").



%% 
%% echoサーバにメッセージ送信
%% 
print(Term) ->
    eserver ! {print, Term}.



%% 
%% echoサーバの停止
%% 
stop() ->
    eserver ! {exit}.



loop() ->
    receive
	{print, Term} ->
	    io:format("~s (reply from echo server)~n",[Term]),
	    loop();
    	{exit} ->
	    ok;
	Other ->
	    io:format("undefined message: ~p~n", [Other]),
	    loop()
    end.


特につまづくポイントはないのかな?
ヒントの通りにサーバプロセスをregisteredにして,exitの時はloopの再帰を止めてあげる.

実行結果

bash-3.2$ erlc ./echo.erl
bash-3.2$ erl
Eshell V5.6.3  (abort with ^G)
1> echo:start().
echo server is running....
ok
2> echo:print("nya!!").
nya!! (reply from echo server)
{print,"nya!!"}
3> echo:stop().
{exit}
4> 
Ex.4-2
%% 
%% Excersize 4-2
%% The Process Ring
%%
%% 

-module(ring).
-export([start/3, quit/0, init/0, init/1]).



%% 
%% ringサーバの起動
%% 
start(M, N, Message) ->
    put(messagenum, M),    % 回っているメッセージ数を保管しておく
    create_ring(N),
    send(M, Message).



%% 
%% node0にM個のMessageを送信
%% 
send(0,_) ->
    ok;
send(M,Message) ->
    node0 ! {message, Message},
    send(M-1, Message).
    

%% 
%% プロセスリングの生成
%% 
create_ring(N) ->
    Pid = spawn(ring, init, []),
    create_ring(N, N-1, Pid).

create_ring(_N,1,NextPid) ->
    Pid = spawn(ring, init, [NextPid]),
    register(node0, Pid);
create_ring(N,C,NextPid) ->
    Pid = spawn(ring, init, [NextPid]),
    create_ring(N, C-1, Pid).



%% 
%% 回っているメッセージを止める
%% 
quit() ->
    N = get(messagenum),    % 回っているメッセージ数を調べる
    node0 ! {quit, N}.



%% 
%% プロセス生成時のイニシャライザ
%% 
init() ->
    put(next, node0),				% 最後に生成されたノードはnextに最初のノードを定める
    io:format("init: ~p: next is ~p ~n",[self(), get(next)]),
    loop().
    
init(NextPid) ->
    put(next, NextPid),				% nextに次のノードを設定する
    io:format("init: ~p: next is ~p ~n",[self(), get(next)]),
    loop().



%% 
%% M個のメッセージを無視する
%% 
ignore_mes(0) ->
    ok;
ignore_mes(M) ->
    receive
	{message, _} ->
	    ignore_mes(M-1)
    end.



loop() ->
    receive
	{message, Mes} ->
	    io:format("~p: ~s~n", [self(), Mes]),
	    Next = get(next),
	    Next ! {message, Mes};
	{quit, M} ->
	    ignore_mes(M);
	Other ->
	    io:format("undefined message: ~p~n", [Other])
    end,
    loop().


問題文の言われる通りに作ってみたんだけど,なんか煩雑なコードになってる気がする.
リングプロセスは1つ前に作ったノードプロセスのPidを受け取りに,メッセージの送信先にしてやればOK.
最初に作ったノード(node0)はregisteredなプロセスにしてやって,最後のノードのメッセージ送信先に指定したり,メッセージを回す最初のノードに使う.

回るメッセージを止めるには,node0が回ってるメッセージのM個分を無視してやればいいので,そのようにignore_mes関数を実装してみました.

実行結果

(500ノードのプロセスリングで100のメッセージを回す)
bash-3.2$ erlc ./ring.erl
bash-3.2$ erl
Eshell V5.6.3  (abort with ^G)
1> ring:start(100, 500, "nya!!").
....
2> <0.466.0>: nya!!
2> <0.409.0>: nya!!
2> <0.405.0>: nya!!
2> <0.408.0>: nya!!
2> <0.480.0>: nya!!
2> ring:quit().
....
3> <0.32.0>: nya!!
3> <0.33.0>: nya!!
3> <0.32.0>: nya!!
3> <0.33.0>: nya!!
3> <0.32.0>: nya!!
3> <0.32.0>: nya!!
3> 
(メッセージが止まった!!)