matching on maps

Björn Gustavsson bjorn@REDACTED
Thu May 14 09:06:49 CEST 2020


On Wed, May 13, 2020 at 3:09 PM Andreas Schultz
<andreas.schultz@REDACTED> wrote:
>
> In the OTP-23 blog entry, there is an example of a illegal map match:
>
>   illegal_example(Key, #{Key := Value}) -> Value.
>
> Can someone explain why the compiler couldn't automatically rewrite that to:
>
>    legal_example(Key, Map) when is_map_key(Key, Map) -> maps:get(Key, Map).
>

We actually tried to make your example legal. The transformation of
the code that we did was not to rewrite to guards, but to match
arguments or parts of argument in the right order so that variables
that input variables would be bound before being used. (We would do a
topological sort to find the correct order.) For your example, the
transformation would look similar to this:

legal_example(Key, Map) ->
  case Map of
     #{Key := Value} -> Value;
    _ -> error(function_clause, [Key, Map])
  end.

In the prototype implementation, the compiler could compile the
following example:

convoluted(Ref,
       #{ node(Ref) := NodeId, Loop := universal_answer},
       [{NodeId, Size} | T],
       <<Int:(Size*8+length(T)),Loop>>) when is_reference(Ref) ->
    Int.

Things started to fall apart when variables are repeated. Repeated
variables in patterns already have a meaning in Erlang (they should be
the same), so it become tricky to understand to distinguish between
variables being bound or variables being used a binary size or map
key. Here is an example that the prototype couldn't handle:

foo(#{K := K}, K) -> ok.

A human can see that it should be transformed similar to this:

foo(Map, K) ->
  case Map of
    {K := V} when  K =:= V -> ok
  end.

Here are few other examples that should work but the prototype would
refuse to compile (often emitting an incomprehensible error message):

bin2(<<Sz:8,X:Sz>>, <<Y:Sz>>) -> {X,Y}.

repeated_vars(#{K := #{K := K}}, K) -> K.

match_map_bs(#{K1 := {bin,<<Int:Sz>>}, K2 := <<Sz:8>>}, {K1,K2}) -> Int.

Another problem was when example was correctly rejected, the error
message would be confusing.

Because much more work would clearly be needed, we have shelved the
idea for now. Personally, I am not sure that the idea is sound in the
first place. But I am sure of one thing: the implementation would be
very complicated.

/Björn

-- 
Björn Gustavsson, Erlang/OTP, Ericsson AB


More information about the erlang-questions mailing list