Записи в шаблонах - PullRequest
       36

Записи в шаблонах

4 голосов
/ 31 июля 2011

Я изучаю эрланг и спотыкаюсь о каком-то поведении, которое не совсем понимаю.Возьми этот кусок кода.(Я знаю, что существуют библиотеки для того, что я программирую, но, как я уже сказал, я делаю это в образовательных целях):

-module (codec).
-compile (export_all).
-record (node, {symbol, weight, order, left, right, parent} ).
-record (tree, {root, nodes} ).

highestOrderForWeight (Weight, Tree) ->
    lists:max ( [Node#node.order || Node <- Tree#tree.nodes, Node#node.weight == Weight] ).

swapMaybe (Node, Tree) ->
    case highestOrderForWeight (Node#node.weight, Tree) of
        Node#node.order -> pass; 
        Node#node.parent -> pass;
        Tree#tree.root -> pass;
        Partner -> io:format ("Swapping ~p with ~p.~n", [Node#node.order, Partner] )
    end.

Компилятор совсем не удивлен моим кодом:

./so.erl:11: illegal pattern
./so.erl:12: illegal pattern
./so.erl:13: illegal pattern
error

По-видимому, возникают некоторые проблемы с обработкой записей в шаблонах, потому что, когда я изменяю свой код на этот неуклюжий обходной прием, он прекрасно компилируется:

swapMaybe2 (Node, Tree) ->
    [Order, Parent, Root] = [Node#node.order, Node#node.parent, Tree#tree.root],
    case highestOrderForWeight (Node#node.weight, Tree) of
        Order -> pass; 
        Parent -> pass;
        Root -> pass;
        Partner -> io:format ("Swapping ~p with ~p.~n", [Node#node.order, Partner] )
    end.

Вопросы:

  • Как получить доступ к полям записи в шаблонах?
  • Если это невозможно, почему так?
  • Если это невозможно сделатьИтак, что является обычной практикой, чтобы обойти это?

Ответы [ 3 ]

6 голосов
/ 31 июля 2011

На самом деле записи - это просто синтаксический сахар времени компиляции, и вы можете посмотреть на реальные конструкции, используя 'E' параметр компилятора . Например, Node#node.order будет заменен чем-то вроде этого:

case Node of
    {node,_,_rec0,_,_,_} ->
        rec0;
    _ ->
        error({badrecord,node})
end

И, конечно, когда вы пытаетесь использовать Node#node.order, поскольку компилятор скороговорки сообщает illegal pattern для этой конструкции.

Вашу функцию swapMaybe можно переписать так:

swapMaybe(#node{order=Order, parent=Parent}, Tree=#tree{root=Root}) ->
    case highestOrderForWeight (Weight, Tree) of
        Order -> pass; 
        Parent -> pass;
        Root -> pass;
        Partner -> io:format ("Swapping ~p with ~p.~n", [Order, Partner] )
    end.
4 голосов
/ 31 июля 2011

На самом деле невозможно использовать записи в операторах case так, как вы это делали. Записи сопоставления с образцом работают следующим образом:

 swapMayBe2(#node{order=Order, parent=Parent, root=Root} = Node, Tree) ->
     ...

Это связывает Order с полем order и т. Д.

Посмотрите Руководство пользователя примеров программирования на Erlang: http://www.erlang.org/doc/programming_examples/records.html#id62786

3 голосов
/ 01 августа 2011

Шаблон не является произвольным выражением, которое оценивает то, с чем вы хотите сопоставить - вы не можете, например, написать:

  case ... of
      1 + 2 -> ...

и ваша попытка сопоставить со значением полязапись:

  case some_integer(...) of
      Node#node.order -> ...

- это действительно то же самое.Шаблон всегда имеет форму конструктора - он описывает форму вещи, а не способ ее вычисления.Как вы заметили, можно использовать предварительно созданные переменные:

  Order = Node#node.order,
  case some_integer(...) of
      Order -> ...

Более распространенное решение - поместить вычисленное значение в охрану, если нужное выражение настолько простое, что оно разрешено в охранниках:

case some_integer(...) of
    Value when Value =:= Node#node.order -> ...

Если выражения короткие, возможно, вы захотите объединить их в одном предложении, используя точку с запятой в качестве разделителя в страже:

case some_integer(...) of
    V when V =:= Node#node.order ; V =:= Node#node.parent ; V =:= Node#node.root ->
        ...;
    Other ->
        ...
end

(Наконец, какстиль, пожалуйста, не ставьте пробел между именем функции и открывающей скобкой списка аргументов.)

...