【发布时间】:2014-10-18 23:49:57
【问题描述】:
我是函数式编程的新手,刚从 haskell(不太喜欢)切换到 erlang(非常喜欢)。当我作为一名自学者学习时,我偶然发现了these Exercises 并开始学习它们。
我就这个问题来了:
- 编写一个启动2个进程的函数,并发送一条消息M 时间在他们之间向前和向后。消息有后 已发送进程应正常终止。
我这样解决了它并且它有效(也许它可以做得更好;任何评论都非常感谢):
-module (concur).
-export ( [pingpong/1, pingpong/2] ).
pingpong (Msg, TTL) ->
A = spawn (concur, pingpong, ["Alice"] ),
B = spawn (concur, pingpong, ["Bob"] ),
B ! {A, TTL * 2, Msg}.
pingpong (Name) ->
receive
{From, 1, Msg} ->
io:format ("~s received ~p and dying.~n", [Name, Msg] ),
exit (From);
{From, TTL, Msg} ->
io:format ("~s received ~p.~n", [Name, Msg] ),
From ! {self (), TTL - 1, Msg},
pingpong (Name)
end.
真正的问题是下一个练习:
2) 编写一个函数,在一个环中启动 N 个进程,并发送一个 消息 M 次围绕环中的所有进程。之后 消息已发送,进程应正常终止。
由于我没有将消息发送回其发起者,而是发送到链中的下一个节点,因此我必须以某种方式将接收者的进程传递给发送进程。所以我想象这个函数看起来像这样:
pingCircle (Name, Next) ->
...
receive {TTL, Msg} -> Next ! {TTL - 1, Msg}
...
但是我该如何开始这整个事情。当我在圈子中生成第一个函数时,我仍然没有生成下一个节点,因此我不能将它作为参数传递。所以我幼稚的方法不起作用:
First = spawn (concur, pingCirle, ["Alice", Second] ),
Second = spawn (concur, pingCirle, ["Bob", Third] ),
...
同样,将下一个节点的 spawn 调用作为参数递归传递给它的前任的方法,也不能解决如何关闭圆圈的问题,即将最后一个节点传递给第一个节点。
问题是: 如何建立这个圈子?
编辑:
感谢您的出色回答,我成功实现了我的意图。至此这个问题就解决了。
一种可能的解决方案是:
-module (concur).
-export ( [pingCircle/3, pingCircle/2] ).
pingCircle (Names, Message, TTL) ->
Processes = lists:map (fun (Name) -> spawn (?MODULE, pingCircle, [Name, nobody] ) end, Names),
ProcessPairs = lists:zip (Processes, rot1 (Processes) ),
lists:map (fun ( {Process, Recipient} ) -> Process ! {setRecipient, Recipient} end, ProcessPairs),
Circle = lists:map (fun ( {Process, _} ) -> Process end, ProcessPairs),
hd (Circle) ! {Message, TTL - 1, lists:last (Circle) }.
rot1 ( [] ) -> [];
rot1 ( [Head | Tail] ) -> Tail ++ [Head].
pingCircle (Name, Recipient) ->
receive
{setRecipient, NewRecipient} ->
pingCircle (Name, NewRecipient);
{Message, 0, Originator} ->
io:format ("~s received ~p with TTL 0 and dying.~n", [Name, Message] ),
if
Originator == self () -> io:format ("All dead.~n");
true -> Recipient ! {Message, 0, Originator}
end;
{Message, TTL, Originator} ->
io:format ("~s received ~p with TTL ~p.~n", [Name, Message, TTL] ),
if
Originator == self () -> Recipient ! {Message, TTL - 1, Originator};
true -> Recipient ! {Message, TTL, Originator}
end,
pingCircle (Name, Recipient)
end.
这是我的peer review link。
【问题讨论】:
-
+1 只是为了自学。顺便说一句,如果您想对已经正确的代码提出建设性的批评,您可以随时尝试codereview.stackexchange.com。
-
+1 评论 - 这很酷,感谢您的信息!
-
我也+1。这将有助于处理这种新语言。
标签: concurrency erlang