Выборочный прием в 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]

Я понимаю, что этот код сначала просматривает все сообщения с высоким приоритетом, а затем сообщения с низким приоритетом. Я не понимаю, как возвращается значение [высокий, высокий, низкий, низкий], поскольку я не вижу, где они связаны вместе.


person tkblackbelt    schedule 10.06.2012    source источник
comment
Не сцеплено, объединено. конкатенация - это когда у вас есть два списка, L1 и L2, и объединяете их: L1 ++ L2. Согласование - это когда у вас есть элемент E и список L, а затем формируется расширенный список [E | L].   -  person I GIVE CRAP ANSWERS    schedule 11.06.2012


Ответы (3)


Как строится окончательное возвращаемое значение ...

Когда [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, high}, {7, low}, {1, low}, {17, high}. В Erlang сообщения в почтовом ящике Не помещаются в очередь в порядке очереди. Предложение receive может быть разборчивым. Он просматривает все сообщения в почтовом ящике и «выбирает» те, которые ему нужны. В нашем случае {15, high} и {17, high} выбираются первыми согласно {Priority, Msg} when Priority > 10. После этого берет на себя функция normal/0. И {7, low}, {1, low} обрабатываются (согласовываются) по порядку. Наконец-то мы получили [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}]
person Ning    schedule 11.06.2012
comment
Я написал код, о котором спрашивал OP (я считаю, что это мой приоритет в Learn You Some Erlang), и я одобряю этот ответ. - person I GIVE TERRIBLE ADVICE; 19.06.2012

они объединены здесь

[Msg | important()]

это important() - функция, поэтому у нее есть возвращаемое значение, пока вы запустите ее в REPL, он будет печатать возвращаемое значение из функции. Это значение является результатом [Head | Tail] построения списка из import()

important() вот штатная функция :)

Это полезно?

person Jakub Oboza    schedule 10.06.2012
comment
Спасибо за быстрый ответ. Таким образом, даже сообщения с низким приоритетом, полученные от вызова normal () в after, объединяются в список с высоким приоритетом в [Msg | important ()] предложение? - person tkblackbelt; 11.06.2012
comment
все. Также, вероятно, он затопит ваш барана, если вам нужно много сообщений, поэтому вы должны скрыть его в хвостовой рекурсивной функции. Я не знаю, что вы пытаетесь построить, потому что в целом это должен быть gen_server с очередью приоритета, как внутри структуры данных. Вы пытаетесь сделать это внутри очереди сообщений процесса, и эта вещь ограничена, поэтому в целом это плохая идея. - person Jakub Oboza; 11.06.2012

Все функции 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 является особенным, поскольку оно немедленно истекает, но гарантирует сначала поиск по всей очереди сообщений на предмет совпадения сообщений.

person rvirding    schedule 11.06.2012