2012-06-10 12 views
9

私はErlangの学習を始めました。このコードとちょっと混乱しています。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] 

このコードでは、すべての優先度の高いメッセージが優先され、次に優先度の低いものが優先されます。戻り値がどのように[高値、高値、低値、低値]になっているのか混乱しています。彼らはここで

[Msg | important()] 

concatedさ

+1

連結されていません。連結は、あなたが 'L1'と' L2'の2つのリストを持ち、それらを連結するときです: 'L1 ++ L2'。 consiningは要素 'E'とリスト' L'を持ち、拡張リスト '[E | L] 'となる。 –

答えて

14

... [Msg | important()]が初めて返される

は、最終戻り値の形式が決定されます。唯一の心配は、最終的な戻り値の詳細がまだすべてわからないということです。 [Msg | important()]important()は引き続き評価されます。以下は、最終戻り値[high,high,low,low]がどのように構築されているかを示したものです。機能important/0でコードがどのように動作する

[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 

...

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

処理順序を明らかに変更されたバージョン...

我々は処理(コンス)順番がより明確にするために、コードを少し変更することができ

-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}] 
+2

私はOPが尋ねたコードを書きました(これは私がErlangの学びの中で私の優先事項であると信じています)、私はこの答えを承認します。 –

4

それは、戻り値を持っているように、このimportant()あなたはREPLでこれを実行している間、彼は関数からの戻り値を出力します、関数です。この値は、ここでimport()

important()から[Head | Tail]リストの建物の影響で通常の関数である:)

それは参考になりましたか?

+0

クイック返信をありがとう。したがって、afterのnormal()コールから受け取った低優先順位のメッセージでさえも、[Msg | important()]節? – tkblackbelt

+0

すべて。もしあなたがメッセージのようなものを持っているならば、おそらくそれはあなたのRAMをあふれさせるだろう。だからあなたはそれを尾の再帰関数に変換すべきである。私はあなたが何を構築しようとしているのかよく分かりません。なぜなら一般的に内部データ構造のような優先度を持つgen_serverでなければならないからです。あなたはプロセスメッセージキューの中でそれをしようとしており、このことは限られているので、一般的には悪い考えです。 –

2

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

normal/0が呼び出されると、important/0が再度呼び出されることはないので、優先度の高いメッセージの特別な処理はありません。また、important/0は、実際にキューにすでに存在する優先度の高いメッセージを処理します。それ以上見つからない場合は、normal/0を呼び出します。

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

関連する問題