1

私は Erlang を初めて使用し、あるプロセスからプロセスのリストにメッセージを送信する方法を理解しようとしています。

Pid を含むリストを保持するデータ構造があるとします。Pid にメッセージ「M」を Pid のリストに送信させるにはどうすればよいですか。リストの各要素には、文字列 (名前を表す) と Pid の 2 つの要素があります。私が思いついたのは次のとおりです。

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 のリストを正しくパターン一致させていないということです。

基本的に、新しいメッセージが到着するのを常に待っている「ルーパー」と呼ばれる機能があります。タイプのメッセージを受信したとき

{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

編集

ブロードキャスト機能を追加した後。looperfuncitonに送信して受け取っているのはfriendsatomです。アトムでリスト内包表記を行うことはできません。リストでのみ行うことができます。そのため、演算子bedargを使用しようとすると取得されます。<-

ロジックを分解するには: pid と atom を自分自身に送信し、1 行後に受信します。なぜそれをする必要があるのか​​ わかりませんか?基本的に同じでまっすぐ行くことができます:

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

これで、 に送信しているのは pid のリストではなく、atom であることがはっきりとわかりますlooper


あなたが受け取っているエラーは、組み込みの Erlang 関数 ( + !) を間違った型で呼び出していることを示唆しています。したがってFriends、いずれかはプロセスでRはないか、実行できるものではないと思います- 1。リスト内包をデバッグする前に、それらを出力してみてください。

次のようなガードを使用することもできます

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

ただし、パターン一致しないメッセージは無視します。

マイナーノート

それがあなたがやろうとしていることかどうかはわかりませんが、それらも役立つかもしれません。

私が気付くことができることの1つは、あなたが tuple を送信しているという事実です {send_message, {M, R-1, ID, Friends}}。それがあなたのメッセージ全体であり、これだけが受け取られます。Erlang は魔法のように何も追加しません。このような{From, {send_message, {M, R, ID, Friends}}}FromF ! {self(), {send_message, {M, R-1, ID, Friends}}}

他に注意すべき点は、「より長い」関数でのパターン マッチングです。Friends変数は関数の引数としてバインドされています (値に割り当てられています)。したがって、あなたがしていることをしreceive {From, {send_message, {M, R, ID, Friends}}}ているときは、メッセージタイプ (2 タプル、2 タプル、4 タプル)、アトムsend_message 、および Friendsリストのパターン マッチングです。loopつまり、関数が最初に呼び出されたのとまったく同じ友人のリストを受信した場合にのみ、「送信ロジック」を実行します。そして、他のすべてのメッセージ (terminateもちろん除く) は無視されます (メッセージ ボックスに残るだけです)。新しい友達を期待している場合は、バインドされていない変数でのパターン マッチ (関数を短くしておくと、この Erlang の落とし穴に役立ちます)。

于 2014-10-04T20:08:29.693 に答える