11

だから、Erlang の学習を始めたのですが、このコードの塊に少し混乱しています。

 -module(prior).
 -compile(export_all).


    important() ->
      receive
    { Priority, Msg } when Priority > 10 ->
      [Msg | important()]
  after 0 ->
     normal()
  end.

normal() ->
  receive
    { _, Msg } -> 
      [Msg | normal()]
  after 0 ->
      []
  end.

を使用してコードを呼び出しています。

    10> self() ! {15, high}, self() ! {7, low}, self() ! {1, low}, self() ! {17, high}.
    {17,high}
    11> prior:important(). 
        [high,high,low,low]

このコードは優先度の高いすべてのメッセージを最初に通過し、次に優先度の低いメッセージを通過することを理解しています。戻り値がどのように[高、高、低、低]であるかについて混乱しています。それらが連結されている場所がわからないためです。

4

3 に答える 3

17

最終的な戻り値の作成方法...

[Msg | important()]が初めて返されるとき、最終的な戻り値の形式が決定されます。唯一の懸念は、最終的な戻り値の詳細がまだすべてわかっていないことです。したがって、important()[Msg | important()]引き続き評価されます。以下は、最終的な戻り値[high,high,low,low]がどのように構築されるかを示しています。

[high | important(                      )]  <---- Defines the final form
        ---------------------------------
        [high | important(             )]   <---- Adds more details
                ------------------------
                normal(                )    <---- Adds more details
                ------------------------
                [low | normal(        )]    <---- Adds more details
                       ----------------
                       [low | normal()]     <---- Adds more details
                              --------
                              [      ]      <---- Adds more details
------------------------------------------
[high | [high | [low | [low | []]]]]
[high,high,low,low]                         <---- The final return value

コードの仕組み...

関数important/0では、after 0単に「メッセージが来るのを待たない」という意味です。メールボックスにメッセージがある場合は、それを調べます。ない場合は、そこでnormal()待つのではなく、続けて(実行)します。メールボックスには、すでに{15、高}、{7、低}、{1、低}、{17、高}があります。Erlangでは、メールボックス内のメッセージは先着順でキューに入れられません。receive条項は厄介な場合があります。メールボックス内のすべてのメッセージをスキャンし、必要なメッセージを「選択」します。この場合、{15、high}{17、high}が最初に選択され{Priority, Msg} when Priority > 10ます。その後、関数normal/0が引き継ぎます。そして{7、低}、{1、低}順番に処理(consed)されます。最後に、を取得し[high,high,low,low]ました。

処理順序を明らかにする修正バージョン...

処理(consing)の順序をより明確にするために、コードを少し変更できます。

-module(prior).
-compile(export_all).

important() ->
    receive
    {Priority, Msg} when Priority > 10 ->
        [{Priority, Msg} | important()] % <---- Edited
    after 0 ->
    normal()
    end.

normal() ->
    receive
    {Priority, Msg} -> % <---- Edited
        [{Priority, Msg} | normal()] % <---- Edited
    after 0 ->
        []
    end.

シェルで実行します。

4> c(prior).
{ok, prior}
5> self() ! {15, high}, self() ! {7, low}, self() ! {1, low}, self() ! {17, high}.
{17,high}
6> prior:important().
[{15,high},{17,high},{7,low},{1,low}]
于 2012-06-11T00:46:07.023 に答える
4

それらはここに連結されています

[Msg | important()]

これimportant()は関数であるため、戻り値があります。これを REPL で実行すると、関数からの戻り値が出力されます。この値は、[Head | Tail]からのリスト構築の効果ですimport()

important()ここに通常の関数があります:)

役に立ちましたか?

于 2012-06-10T20:09:49.010 に答える
2

すべてのErlang関数は常に値を返します。この関数important/0は優先度の高いメッセージを受信し、式を再帰的に呼び出して、受信する最新のメッセージと他のすべてのメッセージを[Msg | important()]含むリストを作成します。から返されるのはこのリストです。優先度の高いメッセージがなくなると、代わりに呼び出して残りのすべてのメッセージを読み取ります。それを読んだメッセージは、同じようにリストとして返されます。これが返され、メッセージを返したのと同じリストに返されます。Msgimportant/0important/0important/0normal/0normal/0important/0important/0

一度呼び出されると、二度と呼び出されることはないnormal/0ため、優先度の高いメッセージの特別な処理は行われないことに注意してください。important/0またimportant/0、キューにすでに存在する優先度の高いメッセージのみを実際に処理します。これ以上見つからない場合は、を呼び出しますnormal/0

タイムアウト値0は、すぐにタイムアウトするという点で特別ですが、最初にメッセージキュー全体で一致するメッセージを検索することが保証されます。

于 2012-06-11T00:44:04.547 に答える