Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selective receiving in Erlang

Tags:

erlang

erl

So I've started learning Erlang and I'm a little confused with this chunk of code.

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

I am calling the code using.

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

I understand that this code will go through all the high priority messages first and then the low priority ones. I'm confused as to how the return value is[high,high,low,low], since I don't see where they are concatenated together.

like image 632
tkblackbelt Avatar asked Jun 10 '12 20:06

tkblackbelt


2 Answers

How the final return value is constructed...

When [Msg | important()] is being returned for the first time, the form of the final return value is determined. The only concern is, we don't know all the details of the final return value yet. So the important() in the [Msg | important()] will continue being evaluated. The following is an illustration of how the final return value [high,high,low,low] is constructed.

[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

How the code works...

In function important/0, after 0 simply means "I don't wait for messages to come" -- if there is any message in my mailbox, I will look at it; if there isn't any, I will keep going (execute normal()) rather than waiting there. In the mailbox, there are {15, high}, {7, low}, {1, low}, {17, high} sitting there already. In Erlang, the messages in the mailbox are Not queued in a first-come-first-serve order. The receive clause can be picky. It scans through all the messages in the mailbox and "picks" the ones it desires. In our case, {15, high} and {17, high} get picked first according to {Priority, Msg} when Priority > 10. After that, the function normal/0 takes over. And {7, low}, {1, low} get processed (consed) in order. Finally, we got [high,high,low,low].

A modified version that reveals the processing order...

We can modify the code a little bit in order to make the processing (consing) order more explicit:

-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 it in the 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}]
like image 189
Ning Avatar answered Oct 06 '22 01:10

Ning


they are concated here

[Msg | important()]

this important() is a function so it has a return value, while you run this in REPL he will print return value from function. This value is effect of [Head | Tail] list building from import()

important() here is a regular function :)

Is it helpful ?

like image 30
Jakub Oboza Avatar answered Oct 05 '22 23:10

Jakub Oboza