You've probably heard (and written) some recursive functions/methods before. Chances are you've also heard that recursive functions might be more expensive when compared to a non-recursive alternative.

Let's see what is probably the simples example of a recursive function, the factorial implementation. Here we define two clauses of `Factorial.recursive_factorial/1`

, on for `0`

(which returns `1`

) and another for any other value:

```
defmodule Factorial do
def recursive_factorial(0), do: 1
def recursive_factorial(n), do: n * recursive_factorial(n-1)
end
```

On each call of `recursive_factorial(n)`

we multiply `n`

by the result of `recursive_factorial(n-1)`

(which is a recursive call until `n`

reaches `0`

). On every step we need to keep the current value of `n`

so we can multiply it once `recursive_factorial(n-1)`

is returned.

This is why recursive calls are usually considered to be more expensive (specially in terms of space), each call requires the stack to be saved until the result comes back. Saving a stack, even if it is just that `n`

might start causing trouble when the number gets too high (say `500_000`

or more, depending on where you're running it).

But there is something we can do to make it better and as performant as the non recursive alternatives

## Tail Recursion

Take a look at this other implementation and compare it to the previous one:

```
defmodule Factorial do
def tail_recursive_factorial(n), do: tail_recursive_factorial(n, 1)
defp tail_recursive_factorial(0, acc), do: acc
defp tail_recursive_factorial(n, acc), do: tail_recursive_factorial(n-1, acc*n)
end
```

The first call to `Factorial.tail_recursive_factorial/1`

starts the process by calling the private `Factorial.tail_recursive_factorial/2`

which does the recursive process.

Notice that the multiplication is now passed to the recursive call using the second argument. This means that there is no need to store the function stack for each call!

Each call now has everything it needs and the stack can be discarded as soon as the recursive call starts. The end clause here is when `n`

is `0`

and it just returns the value on `acc`

.

When a recursive function doesn't need to store any temporary value to be used after the recursive call, it is considered a Tail Recursive function. Let's check a more interesting problem.

## The 'Strain' exercise on Exercism

On exercism.io there is a nice little exercise where you're asked to implement two functions, `keep`

and `discard`

. Given a `list`

of items and a function `fun`

, `keep`

will return the list of items where `fun`

returns `true`

and `discard`

will return the list of items where `fun`

returns `false`

.

Me and some friends got together to solve this and our initial implementation of `keep`

was to execute `fun`

on the `head`

of the list and if it is `true`

return a list with the the `head`

and then recurse on `tail`

, if not then just call again ignoring the `head`

of the list:

```
def keep([], _fun) do
[]
end
def keep([head | tail] = list, fun) do
keep_if(list, fun, fun.(head))
end
defp keep_if([head | tail] = list, fun, true) do
[head | keep(tail, fun)]
end
defp keep_if([head | tail] = list, fun, false) do
keep(tail, fun)
end
```

The main problem here is that for each call where `fun`

is true we need to save the value stored on `head`

and after the recursive call finishes, the return has to be appended to a list containing `head`

.

For the test scenarios we had, this wasn't a big issue, but we wanted to go a bit further and think about how to make this a tail recursive function.

Our optimization was similar to what we did for `Factorial.tail_recursive_factorial/1`

, we create an accumulator argument and send it on each call instead of waiting to get the result back. Here is how it ended up looking like:

```
defmodule Strain do
def keep(list, fun) do
keep(list, [], fun)
end
def keep([], filtered, _fun) do
filtered
end
def keep([head | _tail] = list, filtered, fun) do
keep(list, filtered, fun, fun.(head))
end
defp keep([head | tail], filtered, fun, true) do
keep(tail, filtered ++ [head], fun)
end
defp keep([_head | tail], filtered, fun, false) do
keep(tail, filtered, fun)
end
end
```

Another nice exercise to try and apply tail recursive optimization is the 'List Operations' one where you're asked to implement basic functions that we usually take for granted, like `each`

, `map`

, `filter`

etc.

Recursive functions are quite common in functional languages, most of them don't even have loops, so learning about tail recursion and practicing how to implement it is a good investment :)

## Top comments (0)