Elixir 1.3

Chapter 2

Pattern Matching

Assignment:
I Do Not Think It Means What You Think It Means.

Let’s use the interactive Elixir shell, iex,
to look at a really simple piece of code.

 

​iex>​ a = 1
1
​iex>​ a + 3
4

You look at this code and say,
“OK, assign 1 to a variable a, then on the next line we add 3 to a, giving us 4".

But when it comes to Elixir, you'd be wrong.

The assignment succeeds if Elixir can find a way of making the left-hand side equal the right-hand side.

Elixir calls = a match operator.

The left-hand side is a variable and the right-hand side is an integer literal, so Elixir can make the match true by binding the variable a to value 1

​iex>​ a = 1
1
​iex>​ a + 3
4
iex>​ a = 1
​1
​​iex>​ 1 = a
1
​​iex>​ 2 = a
​​**​ (MatchError) no match of right hand side value: 1

1 = a is another match so it passes.
The variable a already has the value 1 so it passes.
2 = a raises an error because it is the equivalent to 2 = 1

More Complex Matches

Elixir lists are created using square brackets

​iex>​ list = [1, 2, 3]
​[1, 2, 3]
​​iex>​ [a, b, c] = list
​[1, 2, 3]
​​iex>​ a
​1
​​iex>​ b
​2
​​iex>​ c
​3

To make the match true,
Elixir bound the variable list to the list [1, 2, 3].

Elixir tries make the left side the same as on the right. The left side is a list containing three variables, and the right is a list of three values, so the two sides could be made the same by setting the variables to the corresponding values.

Pattern Matching

iex>​ list = [1, 2, [ 3, 4, 5 ] ]
[1, 2, [3, 4, 5]]
​iex>​ [a, b, c] = list
[1, 2, [3, 4, 5]]
​iex>​ a
1
​iex>​ b
2
​iex>​ c
[3, 4, 5]

Elixir calls this process pattern matching.
A pattern (the left side) is matched if
the values (the right side) have the
same structure and if each term in the pattern can be matched to the corresponding term in the values.

 

iex>​ list = [1, 2, 3]
[1, 2, 3]
​​iex>​ [a, 1, b ] = list
​​**​ (MatchError) no match of right hand side value: [1, 2, 3]”

Here the 1 (the second term in the list) cannot be matched against the corresponding element on the right side, hence the error.

More Pattern Matching

Which of these will match?

a = [1, 2, 3]

a = 4

4 = a

[a, b] = [ 1, 2, 3 ]

a = [ [ 1, 2, 3 ] ]

[a] = [ [ 1, 2, 3 ] ]

[[a]] = [ [ 1, 2, 3 ] ]

Matches

iex> a = [1, 2, 3]
[1, 2, 3]
iex> a = 4
4
iex> 4 = a
4
iex> [a, b] = [ 1, 2, 3 ]
** (MatchError) no match of right hand side value: [1, 2, 3]
iex> a = [ [ 1, 2, 3 ] ]
[[1, 2, 3]]
iex> [a] = [ [ 1, 2, 3 ] ]
[[1, 2, 3]]
iex> [[a]] = [ [ 1, 2, 3 ] ]
** (MatchError) no match of right hand side value: [[1, 2, 3]]

Ignoring a Value with _ (Underscore)

​iex>​ [1, _, _] = [1, 2, 3]
​[1, 2, 3]
​​iex>​ [1, _, _] = [1, ​"​​cat"​, ​"​​dog"​]
​[1, "cat", "dog"]

If we didn’t need to capture a value during the match, we could use the special variable _ (an underscore).

This acts like a variable but immediately discards any value given to it—in a pattern match, it is like a wildcard.

Variables Bind Once (per Match)

iex>​ [a, a] = [1, 1]
​[1, 1]
​​iex>​ a
​1
​​iex>​ [a, a] = [1, 2]
​​**​ (MatchError) no match of right hand side value: [1, 2]

Once a variable has been bound to a value in the matching process, it keeps that value for the remainder of the match.

But a variable can be bound to a new value
in a subsequent match.

iex>​ a = 1
​1
​​iex>​ [1, a, 3] = [1, 2, 3]
​[1, 2, 3]
​​iex>​ a
​2

Can you force Elixir to use the
existing value of a variable?

Prefix it with ^ (a caret).
In Elixir, we call this the pin operator.

iex>​ a = 1
​1
​​iex>​ a = 2
​2
​​iex>​ ^a = 1
​​**​ (MatchError) no match of right hand side value: 1

​​iex>​ a = 1
​1
​​iex>​ [^a, 2, 3 ] = [ 1, 2, 3 ]      ​# use existing value of a​
​[1, 2, 3]
​​iex>​ a = 2
​2
​​iex>​ [ ^a, 2 ] = [ 1, 2 ]
​​**​ (MatchError) no match of right hand side value: [1, 2]

Which of the following will match?

[ a, b, a ] = [ 1, 2, 3 ]
[ a, b, a ] = [ 1, 1, 2 ]
[ a, b, a ] = [ 1, 2, 1 ]
a = 2
[ a, b, a ] = [ 1, 2, 3 ]
[ a, b, a ] = [ 1, 1, 2 ]
a = 1
^a = 2
^a = 1
^a = 2 - a

Matches

iex> [ a, b, a ] = [ 1, 2, 3 ]
** (MatchError) no match of right hand side value: [1, 2, 3]
    
iex> [ a, b, a ] = [ 1, 1, 2 ]
** (MatchError) no match of right hand side value: [1, 1, 2]
    
iex> [ a, b, a ] = [ 1, 2, 1 ]
[1, 2, 1]
iex> a = 2
2
iex> [ a, b, a ] = [ 1, 2, 3 ]
** (MatchError) no match of right hand side value: [1, 2, 3]
    
iex> [ a, b, a ] = [ 1, 1, 2 ]
** (MatchError) no match of right hand side value: [1, 1, 2]
    
iex> a = 1
1
iex> ^a = 2
** (MatchError) no match of right hand side value: 2
    
iex> ^a = 1
1
iex> ^a = 2 - a
1

Another Way of Looking at the Equals Sign

Joe Armstrong, Erlang’s creator, compares the equals sign in Erlang to that used in algebra.

 

When you write the equation x = a + 1, you are not assigning the value of a + 1 to x.


Instead you’re simply asserting that the expressions
x and a + 1 have the same value. 

Another Another Way of Looking at the Equals Sign

Thank you!

Programming Elixir 1.3 Chapter 02

By Dustin McCraw

Programming Elixir 1.3 Chapter 02

  • 1,021