Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Records in patterns

I am learning erlang and I stumbles over some behaviour I cannot quite understand. Take this piece of code. (I know there are existing libraries for what I am programming, but as I stated, I do this for educational purposes):

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

The compiler is not at all amused about my code:

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

It has appearently some trouble digesting records in patterns, because when I change my code to this clumsy work-around, it compiles fine:

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.

Questions:

  • How do I access record fields in patterns?
  • If it is not possible to do so, why is that so?
  • If it is not possible to do so, what is the common practice to work around that?
like image 414
Hyperboreus Avatar asked Dec 12 '22 10:12

Hyperboreus


2 Answers

Actually records are just a compile time syntactic sugar and you can look at the actual constructs by using 'E' compiler option. For example Node#node.order will be replaced by something like this:

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

And of course when you try to use Node#node.order as a patter compiler reports illegal pattern for this construct.

Your swapMaybe function can be rewritten like this:

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.
like image 96
hdima Avatar answered Dec 24 '22 02:12

hdima


It's indeed not possible to use records in case statements the way you did. Pattern matching records works like this:

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

This binds Order to the field order etc.

Take a look at the Erlang Programming Examples User's Guide: http://www.erlang.org/doc/programming_examples/records.html#id62786

like image 28
WolfgangP Avatar answered Dec 24 '22 00:12

WolfgangP