Elixir Course Online | Prograils - Software Development Company
Elixir Pattern Matching: Course Online | Prograils
For some of you, this chapter might seem a bit confusing, but mechanism described here is extraordinary and easy once you get it right. Get ready for pattern matching in Elixir!
Variable assignment in Elixir pattern matching
In a typical programming language, you can assign a value to a variable in the following way:
var = 100
It means that from now on
x = y * 2
we assume that the value of the left side is the same as the right side. Guess what? In Elixir =
is not an assignment - it's pattern matching, and it's working similar to algebraic equation.
The idea behind pattern matching
Look at the =
operator as a match operator or assertion. It's not an assignment anymore. Match operator has two sides: left and right. It succeeds if Elixir can find a way of making the left-hand side equal the right-hand side. Let's look at this example:
iex> var = 100
100
iex> 100 = var
100
iex> 200 = var
** (MatchError) no match of right hand side value: 100
(stdlib) erl_eval.erl:453: :erl_eval.expr/5
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
(iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
(iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
(iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
(iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
Firstly, we bind 100 to var variable (you can only do that when a variable is on the left side of pattern matching). Secondly, and thirdly an expression is not what you expect from a regular assignment. Pattern matching is about matching not assigning. Since in the second expression 100 equals the value of var (it's 100 as well), it returns 100 value as a result. In the third expression there is no match, 200 is not equal to 100, and therefore we get the error as a result.
Pattern matching with a list
Binding and matching values
You can use Elixir pattern matching with a list:
iex> [1, a, b] = [1, 3, 4]
[1, 3, 4]
iex> a
3
iex> b
4
iex> [1, a, 3] = [1, 3, 4]
** (MatchError) no match of right hand side value: [1, 3, 4]
(stdlib) erl_eval.erl:453: :erl_eval.expr/5
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
(iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
(iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
(iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
(iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
Whenever Elixir can match every term on the left side to its corresponding value on the right side, pattern matching succeeds. When on both sides and in the same sequence order are two different values it'll fail. In the last example 3
is not equal to 4
and therefore pattern matching fails.
Pipe operator
Pattern matching can be used with any data structure. Do you remember pipe operator which we used in a list? Its "magic" shows itself fully in pattern matching where you can use it to extract values from a list:
iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
As you can see the head is bound to the first element and tail is bound to a list containing the rest of elements. This mechanism will be beneficial when dealing with recursive functions.
Single binding
Whenever a variable is bound to a corresponding value, it can't bind once again in the same match.
iex> [a, 200] = [100, 200]
[100, 200]
iex> [a, a] = [100, 200]
** (MatchError) no match of right hand side value: [100, 200]
(stdlib) erl_eval.erl:453: :erl_eval.expr/5
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
(iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
(iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
(iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
(iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
Keep in mind, that this rule applies to one match. You can rebind variable in the next match.
iex> [a, 200] = [100, 200]
[100, 200]
iex> a = 200
200
The pin operator
Sometimes you don't want to rebind variable when using it in pattern matching. Instead, you might want to pattern match against value it represents:
iex> x = 10
10
iex> ^x = 12
** (MatchError) no match of right hand side value: 12
(stdlib) erl_eval.erl:453: :erl_eval.expr/5
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
(iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
(iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
(iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
(iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
iex> ^x = 10
10
This example illustrates how pin operator works. Instead of rebinding the value of variable x
it uses its current value and passes it to pattern matching. In the background, when we match:
^x = 10
it's in fact:
10 = 10
since x was already bound to the value of 10. We can only use this operator inside of pattern matching:
iex> ^x
** (CompileError) iex:1: cannot use ^x outside of match clauses
The underscore operator
In some cases, you don’t care about a particular value in a pattern. It is a common practice to bind those values to the _
underscore operator. Let's examine the following example:
iex> [100, 200, 300] = [100, 201, 300]
** (MatchError) no match of right hand side value: [100, 201, 300]
(stdlib) erl_eval.erl:453: :erl_eval.expr/5
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
(iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
(iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
(iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
(iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
iex> [100, _, 300] = [100, 201, 300]
[100, 201, 300]
First pattern match fails, since 200
value doesn't match with 201
- it's obvious. The second match succeeds, but why? As already noted, when you use _
operator in pattern matching, you don’t care about a particular value in a pattern. Underscore operator is meant to be used in pattern matching only:
iex> _
** (CompileError) iex:2: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions