2
votes

I'm reading the great Joy of Elixir and I'm trying to wrap my head around the order of operations in the pattern matching example.

I've got the list

crew = [  
    %{name: "mal", age: 40},
    %{name: "zoey", age: 36},
]

Now I can use pattern matching to take the first element of the list, and assign the name to a different variable like

[first = %{name: first_name} | others] = crew

I understand that the first element in crew was assigned to first and that the name of first was assigned to first_name:

iex> first
%{age: 40, name: "mal"}
iex> first_name
"mal"

According to the examples I can also assign the name to another variable from right-to-left:

%{name: first_name2} = first

But the same fails when I try it from left-to-right:

iex> first = %{name: first_name3}
** (CompileError) iex:33: undefined function first_name3/0
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1355: :lists.mapfoldl/3

My question is: Why is left-to-right assignment OK within list matching, but fails outside of list matching?

2
Variable has to be already assigned on the right side. - denis.peplin
@denis.peplin so why is this not the case within [first = %{name: first_name} | others] = crew? first_name is on the right side of first - noamt
crew provides the data here - denis.peplin

2 Answers

2
votes

The right side of = (match operator) is evaluated first. In the expression

 first = %{name: first_name3}

It tries to get the value of first_name3, but there's no first_name3 in the scope.

For the expression

[first = %{name: first_name} | others] = crew

you can think of it as

[first = %{name: first_name} = %{age: 40, name: "mal"} | others] = crew

or

others = tl(crew)
head = hd(crew)
first = %{name: first_name} = head

Here's another example:

x = "foo" binds the variable x to string "foo" (because x is unbound at first). Now that x has been bound to "foo", "foo" = x is also a valid expression since "foo" matches x.

1
votes

This is because the way elixir evaluates a sequence. When you start up your iex your environment will be empty. When you type in first = %{name: first_name3} It will start by evaluating the right hand side. Inside of the actual map you are trying to associate the key "name" to the variable first_name3. If first_name3 does not exist in your environment the expression will fail to evaluate and you will get the undefined function error.

this should work:

first_name3 = "John"
first = %{name: first_name3}