Pattern Matching
Match Operator ^
Are you ready for a curveball? In Elixir, the =
operator is actually a match operator, comparable to the equals sign in algebra. Writing it turns the whole expression into an equation and makes Elixir match the values on the left hand with the values on the right hand. If the match succeeds, it returns the value of the equation. Otherwise, it throws an error. Let’s take a look:
x = 1
1
Now let’s try some simple matching:
1 = x
1
2 = x
Let’s try that with some of the collections we know:
list = [1, 2, 3]
[1, 2, 3]
[1, 2, 3] = list
[1, 2, 3]
[] = list
[1 | tail] = list
[1, 2, 3]
tail
[2, 3]
[2 | _] = list
{:ok, value} = {:ok, "Successful!"}
{:ok, "Successful!"}
value
"Successful!"
{:ok, value} = {:error}
Pin Operator
The match operator performs assignment when the left side of the match includes a variable. In some cases this variable rebinding behavior is undesirable. For these situations we have the pin operator: ^
.
When we pin a variable we match on the existing value rather than rebinding to a new one. Let’s take a look at how this works:
x = 1
1
^x = 2
{x, ^x} = {2, 1}
{2, 1}
x
2
Elixir 1.2 introduced support for pins in map keys and function clauses:
key = "hello"
"hello"
%{^key => value} = %{"hello" => "world"}
%{"hello" => "world"}
value
"world"
%{^key => value} = %{:hello => "world"}
Function Clauses:
Pattern matching provides an excellent mechanism to guard against incorrect inputs in Elixir. You can define multiple function clauses with specific patterns to handle different input scenarios. When a function is called, Elixir will try to match the input with the patterns in each clause.
defmodule FunctionClauseExample do
def handle_message({:new_user, name}) do
IO.puts("Welcome new user, #{name}!")
end
end
{:module, FunctionClauseExample, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:handle_message, 1}}
correct_input = {:new_user, "Tim"}
FunctionClauseExample.handle_message(correct_input)
Welcome new user, Tim!
:ok
wrong_input = {:old_user, "Tom"}
FunctionClauseExample.handle_message(wrong_input)
We can implement multiple functions with different argument numbers or differnt clauses
defmodule MultipleFunctionClauseExample do
def handle_message({:new_user, name}) do
IO.puts("Welcome new user, #{name}!")
end
def handle_message({:old_user, name}) do
IO.puts("Welcome old user, #{name}!")
end
end
{:module, MultipleFunctionClauseExample, <<70, 79, 82, 49, 0, 0, 8, ...>>, {:handle_message, 1}}
{:new_user, "Tim"}
|> MultipleFunctionClauseExample.handle_message()
Welcome new user, Tim!
:ok
{:old_user, "Tom"}
|> MultipleFunctionClauseExample.handle_message()
Welcome old user, Tom!
:ok