You are on page 1of 4

3/15/2016

Recursion - Elixir

HOME

INSTALL

GETTING STARTED

LEARNING

DOCS

BLOG

PACKAGES

Recursion

News: Elixir v1.2 released


Search...

1 Loops through recursion


2 Reduce and map algorithms

G ETTI N G ST A RTED

1. Introduction

Loops through recursion

2. Basic types
3. Basic operators

Due to immutability, loops in Elixir (as in any functional programming


language) are written differently from imperative languages. For example, in an
imperative language like JavaScript, one would write:

4. Pattern matching
5. case, cond and if
6. Binaries, strings and char

for(i = 0; i < array.length; i++) {


array[i] = array[i] * 2
}

lists
7. Keywords and maps
8. Modules
9. Recursion

In the example above, we are mutating both the array and the variable i.
Mutating is not possible in Elixir. Instead, functional languages rely on

10. Enumerables and streams

recursion: a function is called recursively until a condition is reached that stops

11. Processes

the recursive action from continuing. No data is mutated in this process.

12. IO and the file system

Consider the example below that prints a string an arbitrary number of times:

13. alias, require and import


14. Module attributes

defmodule Recursion do
def print_multiple_times(msg, n) when n <= 1 do
IO.puts msg

15. Structs
16. Protocols

end

17. Comprehensions

def print_multiple_times(msg, n) do

18. Sigils

IO.puts msg
print_multiple_times(msg, n - 1)
end

19. try, catch and rescue


20. Typespecs and behaviours

end

21. Erlang libraries

Recursion.print_multiple_times("Hello!", 3)

22. Where to go next

# Hello!
# Hello!

M IX A N D OTP

# Hello!

1. Introduction to Mix
Similar to case, a function may have many clauses. A particular clause is
http://elixir-lang.org/getting-started/recursion.html

2. Agent
1/4

3/15/2016

Recursion - Elixir

executed when the arguments passed to the function match the clauses
argument patterns and its guard evaluates to true.
When print_multiple_times/2 is initially called in the example above, the
argument n is equal to 3.

3. GenServer
4. Supervisor and Application
5. ETS
6. Dependencies and umbrella
apps

The first clause has a guard which says use this definition if and only if n is
less than or equal to 1. Since this is not the case, Elixir proceeds to the next
clauses definition.

7. Task and gen-tcp


8. Docs, tests and with
9. Distributed tasks and

The second definition matches the pattern and has no guard so it will be

configuration

executed. It first prints our msg and then calls itself passing n - 1 ( 2) as the
second argument.
Our msg is printed and print_multiple_times/2 is called again, this time
with the second argument set to 1. Because n is now set to 1, the guard in
our first definition of print_multiple_times/2 evaluates to true, and we
execute this particular definition. The msg is printed, and there is nothing left

M ETA -PROG RA M MI N G I N
EL IX I R

1. Quote and unquote


2. Macros
3. Domain Specific Languages

to execute.
S PON SORS

We defined print_multiple_times/2 so that, no matter what number is


passed as the second argument, it either triggers our first definition (known as a
basecase) or it triggers our second definition, which will ensure that we get
exactly one step closer to our base case.

Reduce and map algorithms


Lets now see how we can use the power of recursion to sum a list of numbers:

EL IX I R RA D AR

A weekly Elixir email newsletter


with content curated by
Plataformatec. Subscribe
below.

defmodule Math do
def sum_list([head|tail], accumulator) do
sum_list(tail, head + accumulator)
end
def sum_list([], accumulator) do
accumulator

Elixir
Radar
weekly

Subscribe
now

newsletter

end
end
IO.puts Math.sum_list([1, 2, 3], 0) #=> 6

We invoke sum_list with the list [1, 2, 3] and the initial value 0 as
arguments. We will try each clause until we find one that matches according to
the pattern matching rules. In this case, the list [1, 2, 3] matches against
[head|tail] which binds head to 1 and tail to [2, 3]; accumulator is
http://elixir-lang.org/getting-started/recursion.html

2/4

3/15/2016

Recursion - Elixir

set to 0.
Then, we add the head of the list to the accumulator head + accumulator and
call sum_list again, recursively, passing the tail of the list as its first argument.
The tail will once again match [head|tail] until the list is empty, as seen
below:

sum_list [1, 2, 3], 0


sum_list [2, 3], 1
sum_list [3], 3
sum_list [], 6

When the list is empty, it will match the final clause which returns the final
result of 6.
The process of taking a list and reducing it down to one value is known as a
reducealgorithm and is central to functional programming.
What if we instead want to double all of the values in our list?

defmodule Math do
def double_each([head|tail]) do
[head * 2|double_each(tail)]
end
def double_each([]) do
[]
end
end

iex math.exs

iex> Math.double_each([1, 2, 3]) #=> [2, 4, 6]

Here we have used recursion to traverse a list, doubling each element and
returning a new list. The process of taking a list and mapping over it is known
as a mapalgorithm.
Recursion and tail call optimization are an important part of Elixir and are
commonly used to create loops. However, when programming in Elixir you will
rarely use recursion as above to manipulate lists.

http://elixir-lang.org/getting-started/recursion.html

3/4

3/15/2016

Recursion - Elixir

The Enum module, which were going to see in the next chapter, already
provides many conveniences for working with lists. For instance, the examples
above could be written as:

iex> Enum.reduce([1, 2, 3], 0, fn(x, acc) -> x + acc end)


6
iex> Enum.map([1, 2, 3], fn(x) -> x * 2 end)
[2, 4, 6]

Or, using the capture syntax:

iex> Enum.reduce([1, 2, 3], 0, &+/2)


6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]

Lets take a deeper look at Enumerables and, while were at it, their lazy
counterpart, Streams.

Something is wrong? Edit this page on GitHub.

Previous

Top

Next

2012-2016 Plataformatec. All rights reserved.

http://elixir-lang.org/getting-started/recursion.html

4/4

You might also like