2012-06-10 11 views
9

Así que he comenzado a aprender Erlang y estoy un poco confundido con este trozo de código.Recepción selectiva en 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. 

Estoy llamando al código usando.

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

Entiendo que este código pasará primero por todos los mensajes de alta prioridad y luego por los de prioridad baja. Estoy confundido sobre cómo el valor de retorno es [alto, alto, bajo, bajo], ya que no veo dónde están concatenados juntos.

+1

No concatenados, cons. la concatenación es cuando tienes dos listas, 'L1' y' L2' y las concatenas: 'L1 ++ L2'. Consing es cuando tiene un elemento 'E' y una lista' L' y luego forma la lista extendida '[E | L] '. –

Respuesta

14

¿Cómo se construye el valor de retorno final ...

Cuando se está volviendo [Msg | important()] por primera vez, se determina la forma del valor de retorno final. La única preocupación es que aún no conocemos todos los detalles del valor de retorno final. Por lo tanto, el important() en el [Msg | important()] continuará siendo evaluado. La siguiente es una ilustración de cómo se construye el valor de retorno final [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 

¿Cómo funciona el código ...

En función important/0, after 0 simplemente significa "No espero que los mensajes vienen" - si hay algún mensaje en mi buzón de correo, me lo mirará; si no hay ninguno, continuaré (ejecutar normal()) en lugar de esperar allí.En el buzón, hay {15, alto}, {7, bajo}, {1, bajo}, {17, alto} sentado allí ya. En Erlang, los mensajes en el buzón son No en cola en orden de orden de llegada. La cláusula receive puede ser delicada. Escanea todos los mensajes en el buzón y "selecciona" los que desea. En nuestro caso, {15, alto} y {17, alto} obtener recogido primero de acuerdo con {Priority, Msg} when Priority > 10. Después de eso, toma la función normal/0. Y {7, bajo}, {1, bajo} se procesa (compila) en orden. Finalmente, obtuvimos [high,high,low,low].

Una versión modificada que revela el orden de procesamiento ...

Podemos modificar el código un poco con el fin de hacer que el procesamiento (Consing) Para más explícito:

-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 en el 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

Escribí el código sobre el que OP me preguntó (creo que esta es mi prioridad de recibir en Learn You Some Erlang) y apruebo esta respuesta. –

4

que están aquí concated

[Msg | important()] 

este important() es una función por lo que tiene un valor de retorno, mientras se ejecuta esto en REPL se imprimirá valor de retorno de la función. Este valor es [Head | Tail] efecto de fomento de la lista de import()

important() aquí es una función regular :)

¿Es útil?

+0

Gracias por la respuesta rápida. Por lo tanto, incluso los mensajes de baja prioridad recibidos desde la llamada entrante normal() se concatenan a la lista de alta prioridad en [Msg | importante()] cláusula? – tkblackbelt

+0

todo. También es probable que inunde su ram si tiene muchos mensajes, por lo que debe convertirlo en función recursiva de cola. No sé qué intentas construir porque, en general, debería ser un gen_server con una prioridad que sea dentro de la estructura de datos. Estás tratando de hacerlo dentro de un mensaje de proceso y esto es limitado, por lo que es una mala idea en general. –

2

Todas las funciones de Erlang siempre devuelven un valor. La función important/0 recibirá un mensaje de alta prioridad y luego se llamará recursivamente en la expresión [Msg | important()] que crea una lista que contiene el último Msg y todos los demás mensajes que recibirá important/0. Es esta lista que se devuelve desde important/0. Cuando no haya más mensajes de alta prioridad, entonces important/0 llamará al normal/0 para leer todos los mensajes restantes. Los mensajes que normal/0 leen volverán como una lista de la misma manera important/0. Esto se devolverá al important/0, que luego lo devolverá en la misma lista que devolvió sus mensajes.

Tenga en cuenta que una vez que se ha llamado a normal/0, no habrá un manejo especial de los mensajes de alta prioridad, ya que important/0 nunca se vuelve a llamar. También important/0 realmente solo procesará los mensajes de alta prioridad que ya están en la cola, ya que una vez que no puede encontrar más, llama al normal/0.

El valor de tiempo de espera 0 es especial ya que agota el tiempo de inmediato, pero garantiza buscar primero en toda la cola de mensajes para encontrar los mensajes coincidentes.