Skip to content
, 4 mins read

The beautiful pattern matching

My Elixir journey has just started, but I’m already amazed by its match (=) operator. It’s like discovering a new world, a new beautiful way to write code. What is it? Let the code explain!

The problem

Finding a number between 1 and 1000.

An efficient way to solve find the number is guessing the halfway between low and high number of the range, if the guess is too big, then the number must be between the low number and our guess. In the other hand, if the guess is too small, then we have to look between the guess and the high number.

Note: I took the problem and direction from Programming Elixir by Dave Thomas.

JavaScript solution

Let’s first solve this problem using a familiar language: JavaScript. We can use recursion to find the correct number.

function findNumber(actual, low, high) {
  const guess = Math.floor((low+high)/2)
  console.log( `Your guess ${guess}` )
  if (guess == actual) {
    console.log( 'You are correct!' )
    return guess
  }
  if (guess > actual) {
    return findNumber(actual, low, guess-1)
  }
  return findNumber(actual, guess+1, high)
}

Entering Elixir

matching, not assigning

In Elixir, = is not an assignment, it’s more like an assertion. When x = 1 is success, Elixir binds the variable x to 1 to make the value of the left hand side equal to the value of the right hand side. It still looks like assignment, right? Let’s look at other examples:

iex(3)> 1 = y
** (CompileError) iex:3: undefined function y/0

iex is the interactive shell shipped with Elixir where you can run Elixir code right from shell.

This example gives us compile error because Elixir only tries to work on the left hand side to make the value of the left hand side match the value of the right hand side, that’s why Elixir calls = the match operator.

iex(4)> x = 1
1
iex(5)> 1 = x
1
iex(6)> 2 = x
** (MatchError) no match of right hand side value: 1

This example explains better. On the first line, we match the left hand side with the right hand side by binding the variable x to 1. The second line is success because x is bind to 1 previously, so the value of the left hand side and the right hand side is equal, or matched.

The third line raises an error because x is bound to 1 already, the value of left hand side is 2 while the value of right hand side is 1, that’s why it failed.

More complex matches

Match work with other data types as well, like list

iex(6)> list = [1, 2, 3] 
[1, 2, 3]
iex(7)> [a, b, c] = list
[1, 2, 3]
iex(8)> a
1
iex(9)> b
2
iex(10)> c
3

Here, Elixir tries to make the value of the left hand side the same as the value of the right hand side. The left hand side is a list contain three variable, the right hand side is a list of three values, so two sides can be made the same by setting the variables to corresponding values. And Elixir calls this process pattern matching.

Pattern matching and function arguments

The power of pattern matching reveal when we work with function. Lets solve the problem above using Elixir and pattern matching.

defmodule Chop do
  def guess(actual, range = low..high) do
    guess = div(low+high, 2)
    IO.puts("You guess #{guess}")
    _guess(actual, guess, range)
  end

  defp _guess(actual, actual, _) do
    IO.puts("Correct: #{actual}")
  end

  defp _guess(actual, guess, _low..high) when guess < actual do
    guess(actual, guess+1..high)
  end

  defp _guess(actual, guess, low.._high) when guess > actual do
    guess(actual, low..guess-1)
  end
end

In Elixir, one function can have multiple implementations based on the passed arguments, Elixir tries to match from top to bottom and stop at the first matched function. By using this feature, we can break a big and complex function into much simpler ones and remove the usage of if/else blocks.

  defp _guess(actual, actual, _) do
    IO.puts("Correct: #{actual}")
  end

The first private function will match only if the guess and the actual number are the same. This replace the check if guess is equal to actual number in JS solution above. What a clever approach!!! Our function body now becomes dead simple. Think about how easy it can be tested.

It’s just the beginning

I’m still learning the match operator in Elixir, while using the assignment in JS and PHP everyday at 10up. It’s a little lagging between switches, but it’s fun.

If this is the first time you heard about Elixir, this post is confusing. I don’t try to explain everything or introduce Elixir here, this guide does that much better.