In the previous chapter we covered how anonymous functions use pattern matching to bind their parameter list to the passed arguments. The same is true of named functions. The difference is that we write the function multiple times, each time with its own parameter list and body. Although this looks like multiple function definitions, purists will tell you it’s multiple clauses of the same definition (and they’d be right).
When you call a named function, Elixir tries to match your arguments with the parameter list of the first definition (clause). If it cannot match them, it tries the next definition of the same function (remember, this must have the same arity) and checks to see if it matches. It continues until it runs out of candidates.
Let’s play with this. The factorial of n, written n!, is the product of all numbers from 1 to n. 0! is defined to be 1.
Another way of expressing this is to say
This is a specification of the concept of factorial, but it is also close to an Elixir implementation:
| defmodule Factorial do |
| def of(0), do: 1 |
| def of(n), do: n * of(n-1) |
| end |
Here we have two definitions of the same function. If we call Factorial.of(2), Elixir matches the 2 against the first function’s parameter, 0. This fails, so it tries the second definition, which succeeds when Elixir binds 2 to n. It then evaluates the body of this function, which calls Factorial.of(1). The same process applies, and the second definition is run. This, in turn, calls Factorial.of(0), which is matched by the first function definition. This function returns 1 and the recursion ends. Elixir now unwinds the stack, performing all the multiplications, and returns the answer. This factorial implementation works, but it could be significantly improved. We’ll do that improvement when we look at tail recursion.
Let’s play with this code:
| iex> c "factorial1.exs" |
| [Factorial] |
| iex> Factorial.of(3) |
| 6 |
| iex> Factorial.of(7) |
| 5040 |
| iex> Factorial.of(10) |
| 3628800 |
| iex> Factorial.of(1000) |
| 40238726007709377354370243392300398571937486421071463254379991042993851239862 |
| 90205920442084869694048004799886101971960586316668729948085589013238296699445 |
| ... |
| 00624271243416909004153690105933983835777939410970027753472000000000000000000 |
| 00000000000000000000000000000000000000000000000000000000000000000000000000000 |
| 00000000000000000000000000000000000000000000000000000000000000000000000000000 |
| 00000000000000000000000000000000000000000000000000000000000000000000000000000 |
This pattern of design and coding is very common in Elixir (and almost all functional languages). First look for the simplest possible case, one that has a definite answer. This will be the anchor. Then look for a recursive solution that will end up calling the anchor case.
Here are a couple of examples:
Sum of the first n numbers
Length of a list
One point worth stressing: the order of these clauses can make a difference when you translate them into code. Elixir tries functions from the top down, executing the first match. So the following code will not work:
| defmodule BadFactorial do |
| def of(n), do: n * of(n-1) |
| def of(0), do: 1 |
| end |
The first function definition will always match and the second will never be called. But Elixir has you covered—when you try to compile this, you’ll get a warning:
| iex> c "factorial1-bad.exs" |
| .../factorial1-bad.ex:3: this clause cannot match because a previous clause at |
| line 2 always matches |
One more thing: when you have multiple implementations of the same function, they should be adjacent in the source file.