Elixir: Pattern Matching
In Elixir the =
symbol is not for assignment but used as an operator for pattern-matching. This means that when a variable name is matched to some data it can be rematched, just like in other languages variables are reassigned, but there are some differences. For example:
As you can see in the last two examples, this is not assignment. Assignment would throw an error for expression "goodbye" = a
, because it would instead expect an expression of equality, such as "goodbye" == a
(returning a boolean). However with Elixir’s pattern-matching it is checking that the right and left-hand sides are the same. It is only when they are not that an error is raised, because "caramel"
does not match "goodbye"
.
Pattern-matching on Collections
Collections can be pattern matched on using a pipe operator, like so:
The pipe operator, or |
, is splitting the first element of a list with the remaining elements. This is because an Elixir list is a linked-list, and so [1, 2, 3]
can be thought of as [1 | [2 | [3]]]
. Therefore we could also use a pipe operator like so:
In the same way a list of tuples can be pattern-matched like so:
Pattern-matching Arguments
Pattern-matching is very useful in recursion because arguments can be matched again and again. For instance, if we wanted to iterate over a list of elements we could continuously recurse over the remaining elements, which would grow smaller each time. Here is an example:
When sum
is called with a list of numbers, it splits the list into current_number
and the remaining_numbers
. It adds the current_number
to the recursive call of the sum
function on the remaining_numbers
. When it is called recursively the remaining_numbers
is treated as a new list to be split into an updated current_number
and an updated remaining_numbers
. This continues until the list is empty i.e. there are no more numbers to recurse over. In this case it matches the function def sum([]), do: 0
. That is, when the list is empty, []
, return 0
to be added to the final sum.
Here we can see how pattern-matching was useful for splitting the current number to be added from the remaining numbers in the list, and how pattern-matching was useful in setting a base case so that when the list matched an empty list the recursion ends.