noamt
noamt

Reputation: 7805

Elixir complex pattern matching order

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?

Upvotes: 2

Views: 528

Answers (2)

fhdhsni
fhdhsni

Reputation: 1629

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.

Upvotes: 2

Marcus Gruneau
Marcus Gruneau

Reputation: 827

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}

Upvotes: 1

Related Questions