2012-06-10 6 views
9

Così ho iniziato ad imparare Erlang e sono un po 'confuso con questo pezzo di codice.Ricezione selettiva in 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. 

Sto chiamando il codice utilizzando.

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

Capisco che questo codice passerà prima tutti i messaggi con priorità alta e poi quelli con priorità bassa. Sono confuso su come il valore restituito sia [alto, alto, basso, basso], dal momento che non vedo dove sono concatenati insieme.

+1

Non concatenato, consed. la concatenazione avviene quando si hanno due liste, 'L1' e' L2' e le si concatena: 'L1 ++ L2'. Consing è quando si ha un elemento 'E' e una lista' L' e quindi si forma la lista estesa '[E | L] '. –

risposta

14

Come si costruisce il valore di ritorno finale ...

Quando [Msg | important()] viene restituita per la prima volta, sotto forma di valore di ritorno finale è determinato. L'unica preoccupazione è che non conosciamo ancora tutti i dettagli del valore di ritorno finale. Pertanto locontinuerà a essere valutato. Quanto segue è un'illustrazione di come viene costruito il valore di ritorno finale [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 

Come funziona il codice ...

In funzione important/0, after 0 significa semplicemente "Non mi aspetto che i messaggi a venire" - se c'è qualche messaggio nella mia casella di posta, ho lo guarderà; se non ce n'è, continuerò ad andare avanti (esegui normal()) invece di aspettare lì.Nella casella di posta, ci sono {15, alta}, {7, bassa}, {1, bassa}, {17, alta} già seduti lì. In Erlang, i messaggi nella casella postale sono Non in coda in un ordine first-come-first-serve. La clausola receive può essere pignola. Esamina tutti i messaggi nella casella di posta e "preleva" quelli che desidera. Nel nostro caso, {15, high} e {17, high} vengono prelevati per primi in base allo {Priority, Msg} when Priority > 10. Dopo questo, la funzione normal/0 prende il sopravvento. E {7, low}, {1, low} vengono elaborati (consed) in ordine. Infine, abbiamo ottenuto [high,high,low,low].

Una versione modificata che rivela l'ordine di elaborazione ...

Siamo in grado di modificare il codice un po 'al fine di rendere il trattamento (consing) ordine più esplicito:

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

Run nella shell:

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

Ho scritto il codice richiesto dall'OP (credo che questa sia la mia priorità ricevere in Learn You Some Erlang) e approvo questa risposta. –

4

sono concated qui

[Msg | important()] 

questo important() è una funzione quindi ha un valore di ritorno, mentre si esegue questo in REPL si stamperà valore restituito da funzione. Questo valore è effetto di [Head | Tail] costruzione della lista da import()

important() qui è una funzione regolare :)

E 'utile?

+0

Grazie per la rapida risposta. Quindi anche i messaggi a bassa priorità ricevuti dalla chiamata normale() dopo vengono concatenati all'elenco di priorità alta nel [Msg | importante()] clausola? – tkblackbelt

+0

tutto. Probabilmente anche riempirà la tua ram se ti piacerebbe avere un sacco di messaggi, quindi dovresti copiarlo nella funzione ricorsiva della coda. Non so cosa stai cercando di costruire perché in generale dovrebbe essere un gen_server con una priorità que come all'interno della struttura dei dati. Stai provando a farlo all'interno di un messaggio di processo e questa cosa è limitata, quindi è una cattiva idea in generale. –

2

Tutte le funzioni di Erlang restituiscono sempre un valore. La funzione important/0 riceverà un messaggio con priorità alta e quindi si chiamerà in modo ricorsivo nell'espressione [Msg | important()] che crea un elenco contenente l'ultimo Msg e tutti gli altri messaggi che riceveranno important/0. È questo elenco che viene restituito da important/0. Quando non ci sono più messaggi ad alta priorità, allora important/0 chiamerà invece normal/0 per leggere tutti i messaggi rimanenti. I messaggi che normal/0 leggono verranno restituiti come un elenco nello stesso modo important/0. Questo verrà restituito a important/0 che verrà quindi restituito nella stessa lista in cui ha restituito i suoi messaggi.

Si noti che una volta che è stato chiamato normal/0, non verrà effettuata alcuna gestione speciale dei messaggi con priorità alta come important/0 non viene più richiamato. Inoltre, important/0 elaborerà solo i messaggi ad alta priorità già presenti nella coda, poiché una volta non riesce più a trovarli, quindi chiama normal/0.

Il valore di timeout 0 è speciale in quanto è scaduto immediatamente, ma garantisce di cercare prima l'intera coda dei messaggi per i messaggi corrispondenti.