如何将消息广播到Erlang中的进程列表?

时间:2014-10-04 19:37:14

标签: erlang erlang-shell

我是Erlang的新手,我正在尝试了解如何将消息从一个进程发送到进程列表。

据说我们有一个数据结构,其中包含一个带有Pids的列表。如何让Pid发送消息" M"到Pids列表,其中列表的每个元素都有2个元素:一个字符串(代表一个名字)和Pid? 我想出的是:

broadcast(P, M, R) ->
  P ! {self(), friends},
  receive
    {P, Friends} ->
  P ! {self(), {send_message, {M, R, P, Friends}}}
  end.

looper({Name, Friends, Messages}) ->
{From, {send_message, {M, R, ID, [{FriendPid, FriendName} | FriendTale]}}} ->
  if R =< 0 ->
        From ! {From, {self(), {ID, M}}},
        looper({Name, [{FriendPid, FriendName} | FriendTale], [{ID, M} | Messages]});
     R > 0  andalso FriendTale =/= []->
       FriendPid ! {From, {send_message, {M, R-1, ID, FriendTale}}},
       looper({Name, FriendTale, [{ID, M} | Messages]})
  end;
 terminate ->
    ok
end.

但据我所知,我并没有正确匹配Pids列表,因此我可以提取&#34;来自Pids列表元素的Pid。

基本上,我有一个名为&#34; looper&#34;这是不断等待新消息到来。当它收到类型

的消息时
{send_message, {M, R, ID, [{FriendPid, FriendName} | FriendTale]}}

其中&#34; M&#34;是我想要广播到名为&#34; Friends&#34;的Pids列表的消息。和R只是一个整数。

R基本上是一个整数,表示消息应该走多远。

e.g. 0 = broadcast the message to self,
     1 = broadcast the message to the friends of the pid,
     2 = broadcast the message to the friends of the friends of the pid and so on...

在我设置Pid并设置&#34;友谊&#34;之后我从终端获得了什么? Pids之间是:

1> f().
ok
2> c(facein).
facein.erl:72: Warning: variable 'From' is unused
{ok,facein}
3> {Message, Pid} = facein:start({"Bjarki", [], []}).
{ok,<0.186.0>}
4> {Message, Pid2} = facein:start({"Bjarki2", [], []}).
{ok,<0.188.0>}
5> facein:add_friend(Pid,Pid2).
ok
6> facein:broadcast(Pid,"hello",1).

=ERROR REPORT==== 5-Oct-2014::12:12:58 ===
Error in process <0.186.0> with exit value: {if_clause,[{facein,looper,1,[{file,"facein.erl"},{line,74}]}]}

{<0.177.0>,{send_message,{"hello",1,#Ref<0.0.0.914>}}}

非常感谢任何帮助。 感谢

1 个答案:

答案 0 :(得分:1)


修改

添加brodcast功能后。您收到的发送给looper函数的内容是friends atom。你不能在原子上做列表理解,只能在列表上。这就是您尝试使用bedarg运算符时获得<-的原因。

打破你的逻辑:你把你的pid和atom发送给自己,只是为了以后收到一行。不知道为什么你需要这样做?你可以直截了当地说:

broadcast(P, M, R) ->
  P ! {self(), {send_message, {M, R, P, friends}}}.

现在你可以清楚地看到,你发送给looper是原子,而不是pid列表。


错误您建议您使用错误类型调用某些内置Erlang函数(+ !)。所以我猜想Friends中的一个不是一个过程,或者R不是- 1。也许在列表理解之前尝试将它们打印出来进行调试。

你也可以使用像

这样的守卫
receive
  {From, {send_message, {M, R, ID, Friends}}} when is_integer(R) ->
     %%  ...

但您只会忽略不匹配模式的邮件。

次要说明

我不确定这是不是你想做什么,但那些也可能有帮助。

我可以注意到的一件事是你发送元组的事实 {send_message, {M, R-1, ID, Friends}}。那是你的全部信息,只有这一点才会收到。 Erlang将神奇地添加任何内容,因此如果您指望接收{From, {send_message, {M, R, ID, Friends}}},则需要自己发送此From。像这样F ! {self(), {send_message, {M, R-1, ID, Friends}}}

您可能关注的其他事情是“更长”功能中的模式匹配。 Friends变量被绑定(赋值)作为函数参数。所以当你正在做receive {From, {send_message, {M, R, ID, Friends}}}你正在做的事情时,是消息类型上的模式匹配(两元组,带有四元组的二元组),原子send_message Friends列表。这意味着只有当您收到与最初调用loop函数完全相同的朋友列表时,才会执行“发送逻辑”。所有其他消息(当然除了terminate)都将被忽略(只会留在您的消息框中)。如果你指望接收一些新朋友,对未绑定变量的模式匹配(保持函数简短有助于这个Erlang-gotcha)。