1

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

假设我们有一个包含 Pid 列表的数据结构。如何让 Pid 向 Pid 列表发送消息“M”,其中列表的每个元素都有 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.

但是据我了解,我没有正确匹配 Pid 列表的模式,因此我可以从 Pid 列表的元素中“提取” Pid。

基本上,我有一个名为“looper”的函数,它不断等待新消息的到来。当它收到类型的消息时

{send_message, {M, R, ID, [{FriendPid, FriendName} | FriendTale]}}

其中“M”是我想向名为“Friends”的 Pid 列表广播的消息,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 并设置 Pid 之间的“友谊”后,我从终端得到的是:

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>}}}

任何帮助将不胜感激。谢谢

4

1 回答 1

2

编辑

添加广播功能后。您收到的发送到looper功能的是friends原子。你不能对原子做列表理解,只能在列表上。这就是为什么bedarg当您尝试使用<-运算符时得到的原因。

打破你的逻辑:你把你的 pid 和 atom 发送给自己,只是为了稍后收到一行。不知道你为什么需要这样做?您可以直接使用基本相同的方法:

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

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


您收到的错误提示您正在调用一些+ !类型错误的内置 Erlang 函数 ()。所以我猜其中一个Friends不是一个过程,或者R不是你可以做- 1的事情。也许尝试在列表理解之前将它们打印出来以进行调试。

你也可以使用像

receive
  {From, {send_message, {M, R, ID, Friends}}} when is_integer(R) ->
     %%  ...

但您只会忽略不匹配模式的消息。

小音符

我不确定这是否是您想要做的,但这些也可能有所帮助。

我能注意到的一件事是您正在发送 tuple {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)。

于 2014-10-04T20:08:29.693 回答