Extracted from:
Learn Functional Programming with Elixir
New Foundations for a New World
This PDF file contains pages extracted from Learn Functional Programming with
Elixir, published by the Pragmatic Bookshelf. For more information or to purchase
a paperback or PDF copy, please visit [Link]
Note: This extract contains some colored text (particularly in code listing). This
is available only in online versions of the books. The printed versions are black
and white. Pagination might vary between the online and printed versions; the
content is otherwise identical.
Copyright © 2017 The Pragmatic Programmers, LLC.
All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise,
without the prior consent of the publisher.
The Pragmatic Bookshelf
Raleigh, North Carolina
Learn Functional Programming with Elixir
New Foundations for a New World
Ulisses Almeida
The Pragmatic Bookshelf
Raleigh, North Carolina
Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in this book, and The Pragmatic
Programmers, LLC was aware of a trademark claim, the designations have been printed in
initial capital letters or in all capitals. The Pragmatic Starter Kit, The Pragmatic Programmer,
Pragmatic Programming, Pragmatic Bookshelf, PragProg and the linking g device are trade-
marks of The Pragmatic Programmers, LLC.
Every precaution was taken in the preparation of this book. However, the publisher assumes
no responsibility for errors or omissions, or for damages that may result from the use of
information (including program listings) contained herein.
Our Pragmatic books, screencasts, and audio books can help you and your team create
better software and have more fun. Visit us at [Link]
For sales, volume licensing, and support, please contact support@[Link].
For international rights, please contact rights@[Link].
Copyright © 2017 The Pragmatic Programmers, LLC.
All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise,
without the prior consent of the publisher.
Printed in the United States of America.
ISBN-13: 978-1-68050-245-9
Encoded using the finest acid-free high-entropy binary digits.
Book version: B4.0—October 14, 2017
Contents
Change History . . . . . . . . . . . . v
Introduction . . . . . . . . . . . . . vii
1. Thinking Functionally . . . . . . . . . . 1
Why Functional? 1
Working with Immutable Data 3
Building Programs with Functions 4
Declaring Code 7
Wrapping Up 9
2. Working with Variables and Functions . . . . . . 11
Representing Values 11
Executing Code and Generating a Result 12
Binding Values in Variables 15
Creating Anonymous Functions 17
Giving Functions Names 23
Wrapping Up 30
3. Use Pattern Matching to Control the Program Flow . . . 33
Making Two Things Match 33
Unpacking Values from Various Data Types 35
Control Flow with Functions 44
Expanding the Control with Guard Clauses 48
Elixir Control Flow Structures 52
Wrapping Up 55
4. Dive into Recursion . . . . . . . . . . . 57
Surrounded by Boundaries 57
Conquering Recursion 63
Tail Call Optimization 68
Contents • iv
Functions Without Borders 71
Using Recursion with Anonymous Functions 76
Wrapping Up 77
5. Using Higher-Order Functions . . . . . . . . 79
Creating Higher-Order Functions for Lists 80
Use the Enum 85
Use List Comprehensions 87
Pipelining Your Functions 87
Be Lazy 91
Wrapping Up 100
6. Design Your Elixir Applications . . . . . . . 103
Starting Your Project with Mix 103
Designing Entities with Structs 109
Using Protocols to Create Polymorphic Functions 116
Creating Module Behaviours 122
Wrapping Up 134
7. Handle Impure Functions . . . . . . . . . 137
Pure vs. Impure Functions 138
Controlling the Flow of Impure Functions 141
Trying, Rescuing, and Catching 144
Handling with the Error Monad 149
Using with 153
Wrapping Up 155
A1. Adding Rooms to the Game . . . . . . . . . 159
Bibliography . . . . . . . . . . . . 163
Introduction
As a child, I played some games that were very similar—games like Super
Mario Bros., Donkey Kong, The Lion King, and Aladdin. I could switch between
them without much work; the learning ramp-up was quick. They all shared
the same core mechanics: you move straight to the right, jump on platforms,
avoid being hit by enemies. They were all 2D platform games.
Switching between programming languages is similar. In my work, I have
needed to switch between Ruby, JavaScript, and CoffeeScript, and between
Java, Python, and Objective-C. It wasn’t too painful to switch between them.
All these languages are very different from each other, but in some way they
are similar. I could use object-oriented programming with all of them. When
I learned how to create objects and methods, all the dots started to connect
and the language became familiar quickly.
After playing 2D platform games, I switched to fighting games. They were still
games. They were still 2D. However, the challenges and mechanics were
completely different. Instead of going straight to the right and jumping the
obstacles, I needed to punch and kick the enemies in a limited space. I
needed to think differently to master this type of game.
That’s how I felt when I switched to functional programming. Where were my
objects and methods!? I made the mistake of applying the concepts that I was
used to in a paradigm where they aren’t necessary. I was messing up the code
base. I needed to change my thinking. I couldn’t program like I had before.
Switching to a new paradigm is very different from simply switching between
languages. You need to think differently, or you’ll get in trouble.
I invite you to reset your mind before learning functional programming. After
reading this book you’ll see your old code with a very different perspective.
The best part is that most of the main languages of today support some
functional concepts. Even if you can’t switch to Elixir today, you’ll be able to
apply useful functional concepts in your daily language.
• Click HERE to purchase this book now. discuss
Introduction • iv
Is This Book for You?
This book was tailored for beginners in functional programming and Elixir. I
expect you have some experience in building simple algorithms, debugging
errors, running commands in terminal, and an entry-level knowledge of soft-
ware development. Any experience in others languages will help you out. You
don’t need to be an expert because we’ll start from the scratch.
If you are an object-oriented programmer ready to take the next step, or a
college student graduating and looking for a language to work with, this book
is for you. If you tried to program in Elixir before and have had a hard time
because of the functional programming concepts, this book will teach you
the missing knowledge that you need to become a future expert. If you’re
already an Elixir or functional programming expert, you may find some
valuable tips here, but this book probably isn’t for you.
What’s in This Book?
You’ll find a beginner’s guide to functional programming concepts and at the
same time will be introduced to Elixir. The book is divided into seven chapters:
Chapter 1, Thinking Functionally, on page ? introduces the main concepts
of functional programming that will go along with you through the book. You’ll
learn why functional concepts matter and help you create better software.
In Chapter 2, Working with Variables and Functions, on page ? you’ll start
learning Elixir from scratch: from simple expressions to modules. We’ll explore
the base building block of a functional program: functions. Anonymous and
named functions are introduced here.
Then, in Chapter 3, Use Pattern Matching to Control the Program Flow, on page
?, you’ll learn how to create conditional code with functions. Pattern
matching plays the central role.
Repetition is a fundamental task in any programming language. In Chapter
4, Dive into Recursion, on page ? you’ll learn the functional way: recursive
functions.
In Chapter 5, Using Higher-Order Functions, on page ?, we’ll explore how to
create better functions that hide complex code. We’ll see how to create func-
tions that can receive or return functions; you’ll learn higher-order functions.
Chapter 6, Design Your Elixir Applications, is about creating a larger application
and organizing it. We’ll explore how to model data, create contracts, and
achieve polymorphism using Elixir.
• Click HERE to purchase this book now. discuss
Using Elixir •v
Then, in Chapter 7, Handle Impure Functions, we’ll see the concept that fin-
ishes this journey: how to work with impure functions. We’ll explore four
strategies and see their pros and cons: conditional code, exception handling,
monads, and Elixir’s with.
Using Elixir
Elixir is a functional programming language that runs in the Erlang VM, a
powerful environment to run distributed systems. I’ve chosen Elixir for this
book because of its fun syntax, the vibrant community, and the production-
ready tooling. Elixir syntax let you focus on what’s important while learning
functional programming.
Installing Elixir
Elixir needs Erlang, and most Elixir installers will install Erlang, as well. So,
you don’t need to worry about it. There’s not much to say about it if you follow
the official Elixir installation guide.1 The guide covers everything you need to
know to install Elixir in the main operating systems. Read the guide, install
the latest Elixir version(1.4.4 or newer), and come back here.
Running the Code
For some examples, you will need to write commands in your terminal. They
will look like this:
$ elixir -v
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe]
[kernel-poll:false] [dtrace]
Elixir 1.4.4
The command goes after the $ sign. Press Enter after typing the command to
see the result. If you tried the command elixir -v, the result will show you that
you have Elixir 1.4.4 installed or a newer version.
We’ll also work with some Elixir tools that use the terminal, especially in
Chapter 6, Design Your Elixir Applications. The main tool we’ll use in many
examples is Elixir’s interactive shell, IEx. Try it:
$ iex
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe]
[kernel-poll:false] [dtrace]
Interactive Elixir (1.4.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
1. [Link]
• Click HERE to purchase this book now. discuss
Introduction • vi
You’ll find this interactive shell is very useful to quickly try Elixir code and
concepts, and gather information to debug local and remote systems. Type
the code that runs inside the IEx shell after the iex> prompt. For example:
iex> [Link] "Hello World"
Hello World
:ok
After the iex> prompt, type the command and press Enter to see the result.
Inside the IEx you use autocomplete with the tab button. You can exit using
Ctrl + c two times.
Moreover, some code will look like this:
introduction/hello_world.exs
[Link] "Hello World!"
The top line has the name of the file with an exs (for script files) or ex (for
compiled files) extension. You can execute most of them using the terminal,
like this:
$ elixir hello_world.exs
Hello World!
That’s everything you need to know to use Elixir and run most of the examples
in the book.
Online Resources
You can find all the examples, a form to submit errata, and a community
forum for this book on the the Pragmatic Programmers website.2 Additionally,
you can get in touch with me and other readers in the Elixir community forum
for this book.3
2. [Link]
3. [Link]
• Click HERE to purchase this book now. discuss
CHAPTER 1
Thinking Functionally
Our programming paradigm is changing. If that sentence doesn’t scare you,
let me try again. The rules that govern typical everyday programming are
changing. That doesn’t happen often. When it does, something important is
going on.
You see, languages come and go. Many things might prompt a new language,
such as a new problem (mobile development for Apple’s Swift), a critical limi-
tation (speed for C), or distribution (portability for Java).
When programming paradigms change, something serious is out of balance.
Why Functional?
A programming paradigm consists of the rules and design principles of
building software. A paradigm change is serious business. Something in how
we are building software isn’t meeting the modern demands. We need to
process multiple tasks and huge data fast and reliably. The CPU isn’t getting
faster—we can’t just write code and hope it will be faster with a new CPU
launch. Instead, we have multiple cores or even machines to process stuff.
We need to write code that takes advantage of concurrency and parallelism.
Unfortunately, when you are working in conventional imperative and object-
oriented languages, it’s hard to get it right. Let’s take a closer look.
The Limitations of Imperative
Conventional languages have shared mutating values. This means that many
parts of the program can reference the same value, and it can change.
Mutating values can be dangerous for concurrency; you can easily introduce
hard-to-detect bugs. For example, take a look at this script in Ruby:
list = [1, 2, 3, 4]
[Link]
• Click HERE to purchase this book now. discuss
Chapter 1. Thinking Functionally •2
# => 4
[Link](1)
# => [1, 2, 3, 1]
puts [Link]
# => [1, 2, 3, 1]
In this chapter you’ll see some code examples like the one above. Don’t worry
about the syntax or how the language works. The focus is on the concepts.
Here, you can mutate the data by adding or removing elements. Now imagine
multiple parts of an application running in parallel and having access to this
value at the same time. What could happen if, in the middle of some operation,
the value changes because of another process? It’s hard to predict. It brings
the headaches that many developers face. That’s why many features and
libraries in these conventional languages offer mechanisms to help you lock
and synchronize the changes. However, that’s not the only way. Functional
programming offers a better alternative.
Moving to Functional Programming
Here’s a quick overview: functional programming is a programming paradigm
in which functions are the basic building blocks, all values are immutable,
and the code is declarative.
When you search for functional programming, a lot of unusual terms pop up.
It’s like it was made for mathematicians, not for programmers. It’s no wonder
some developers find functional programming languages have a high initial
barrier to learning.
From Lambda Calculus to Functional Programming
In this book you’ll learn about anonymous functions, free and bound variables, and
functions as first-class citizens. They come from the lambda calculus computation
model, created by Alonzo Church in the 1930s.a This model is the smallest universal
language that can simulate any real computation—that’s Turing complete. If you see
a programming language that has lambdas, you can be sure that Church’s model
has influenced it.
a. [Link]
Enter Elixir, a dynamic, functional language. The simple and pragmatic syntax
of Elixir makes it an accessible programming language for everyone, even for
those who haven’t learned the functional paradigm. Elixir is a robust and
• Click HERE to purchase this book now. discuss
Working with Immutable Data •3
production-ready language, and it lives in the Erlang ecosystem, which has
existed for 30 years delivering software with nine 9s reliability.1
With a functional language like Elixir, you’ll have better use of your CPU
multicores, writing shorter and more explicit code. When you apply the
functional paradigm in a functional language, you write code that lives har-
moniously with the language. But it doesn’t come for free. You must under-
stand and follow these core principles: immutability, functions, and declarative
code. In this chapter, we’ll examine these principles in detail and see how the
functional foundation is better prepared for modern demands. Let’s start with
immutable data.
Working with Immutable Data
Conventional languages use mutating shared values that require thread and
lock mechanisms to work with concurrency and parallelism. In functional
programming, all values you create in your program are immutable. By default,
each function will have a stable value. Then we don’t need lock mechanisms,
simplifying the parallel work. It changes everything when you’re building
software.
Look at this Elixir code:
list = [1, 2, 3, 4]
[Link](list, -1)
# => [4]
list ++ [1]
# => [1, 2, 3, 4, 1]
[Link] list
# => [1, 2, 3, 4]
The value of list is immutable: no matter the operation we apply to it, it will
generate new values. If the list is immutable and each operation has a safe
value, it means the compiler can safely run these three lines in parallel
without affecting the final result. We have the benefits of parallelism just by
writing simple functions. It’s a huge win. You may think: “All this transforma-
tion generating new values will be slow”. It’s not. Elixir has smart data
structures that reuse values in memory, making every operation of transform-
ing values very efficient.
Immutability is showing up more in conventional languages. They usually
provide the immutable mechanism by giving you an immutable data type
1. [Link]
• Click HERE to purchase this book now. discuss
Chapter 1. Thinking Functionally •4
alternative, or a method to turn a value immutable. For example, in Ruby
you can create immutable values using the freeze method:
User = [Link](:name)
users = [[Link]("Anna"), [Link]("Billy")].freeze
# => [#<struct User name="Anna">, #<struct User name="Billy">]
[Link]([Link]("James"))
# => can't modify frozen Array
[Link] = "Karina"
puts [Link]
# => [#<struct User name="Karina">, #<struct User name="Billy">]
In Ruby, when you freeze the array you can’t add or remove items, but you
still can modify the stored objects. I’ve seen many developers falling into this
trap, thinking that by using freeze they were creating a safe immutable value.
It’s easy to make mistakes with mutability, and such mistakes are costly
when you are dealing with concurrency. Although the conventional languages
are adopting some functional programming concepts, they don’t offer you the
full advantage of a functional language ecosystem.
Building Programs with Functions
In functional programming, functions are the primary tool to build a program.
You can’t create a useful program without writing or using functions. They
receive data, complete some operation, and return a value. They are usually
short and expressive.
We combine multiple little functions to create a larger program. The complex-
ity of building a larger application is reduced when the functions have these
properties:
• The values are immutable.
• The function’s result is only affected by the function’s arguments.
• The function doesn’t generate effects beyond the value it returns.
Functions like this are called pure functions. A simple example is a function
that adds 2 to a number:
add2 = fn (n) -> n + 2 end
add2.(2)
# => 4
This takes an input, processes it, and returns a value. This is the way most
functions work. A few functions will be more complex—their result can’t be
predictable and they are known as impure functions. We’ll look at them more
in Chapter 7, Handle Impure Functions, on page ?.
• Click HERE to purchase this book now. discuss
Building Programs with Functions •5
Using Values Explicitly
Functional programming always passes the values explicitly between the
functions, making clear to the developer what are the inputs and outputs.
The conventional object-oriented languages use objects to store a state, pro-
viding methods for operating on it. The object’s state and methods are very
attached to each other. If we change the object’s state, the method invocation
will result in a different value. For example, take a look at this Ruby code:
class MySet
attr_reader :items
def initialize()
@items = []
end
def push(item)
[Link](item) unless [Link]?(item)
end
end
set = [Link]
[Link]("apple")
puts [Link]
# => ["apple"]
[Link]("apple")
puts [Link]
# => ["apple"]
The MySet class doesn’t allow repetead values. When we call [Link], the push
method depends on the set object internal state. As software evolves, the
common tendency is for the object to accumulate more and more internal
states. It generates a complex dependency between the methods and the
states, which can be hard to debug and maintain. We need to be constantly
disciplined about applying good practices.
Functional programming gives us an alternative. We can use the same MySet
example in Elixir, that does the same thing in a different way:
defmodule MySet do
defstruct items: []
def push(set = %{items: items}, item) do
if [Link]?(items, item) do
set
else
%{set | items: items ++ [item]}
end
end
end
• Click HERE to purchase this book now. discuss
Chapter 1. Thinking Functionally •6
set = %MySet{}
set = [Link](set, "apple")
[Link] [Link]
# => ["apple"]
set = [Link](set, "apple")
[Link] [Link]
# => ["apple"]
You’ll learn the details of how to create Elixir functions in Chapter 2, Working
with Variables and Functions, on page ?, and structs in Chapter 6, Design
Your Elixir Applications, on page ?. The most important thing here is that
the operations and data are not attached to each other. While in Ruby
example the operation must be called from a method that belongs to an object
that contains data; in Elixir, the operation exists on its own. The data must
be explicitly sent to the [Link] function. Every time we call it, it generates
a new data structure with updated values. Then we update the set variable
to store the updated value and print it. The push function works with its
arguments and returns a new value. Nothing more.
Using Functions in Arguments
Functions are so interlaced with everything you do in functional programming
that they can be used in the arguments and results of functions:
iex> [Link](["dogs", "cats", "flowers"], &[Link]/1)
["DOGS", "CATS", "FLOWERS"]
Here we are executing a function called [Link], and passing a list ("dogs",
"cats", and "flowers") and a function called [Link]. The [Link] function
knows how to apply the [Link] to each item of the list. The result is a
new list with all words uppercased. Passing functions to other functions is a
powerful and mind-blowing mechanism. You see it in detail in Chapter 5,
Using Higher-Order Functions, on page ?. Functions are the star of the show
in the functional paradigm.
Transforming Values
Elixir’s focus is on the data-transformation flow, and it has a special operator
called pipe (|>) to combine multiple functions’ calls and results. Given a code
that takes a text like "the dark tower", and transforms into a title, "The Dark Tower".
You’ll avoid writing like this:
def titleize(title) do
join_with_whitespace(
capitalize_words(
[Link](title)
• Click HERE to purchase this book now. discuss
Declaring Code •7
)
)
end
To write like this:
def titleize(title) do
title
|> [Link]
|> capitalize_words
|> join_with_whitespace
end
Using pipe, the result of each expression will be passed to the next function.
You’ll learn more about it in Pipelining Your Functions, on page ?. As you
can see, this Elixir function is simple and easy to understand. You can almost
read it as plain English. The function titleize receives a title. The title will be
split, transforming a list of words. The second transformation will be a list of
capitalized words. The final transformation is a unique string separating the
words with whitespaces.
That’s our focus in functional programming. Every basic building block is a
function. Those functions follow principles, like immutability, that help us
build functions that are easier to understand and that are better citizens in
the concurrent world.
Declaring Code
Imperative programming focuses on how to solve a problem, describing each
step as actions. Functional programming is declarative. Declarative program-
ming focuses on what is necessary to solve a problem, describing the data
flow. Programming in a declarative way usually generates less code than the
imperative version. Less code means fewer things to write, more things done,
and fewer bugs. Yay!
To see the difference between imperative and declarative, let’s look at a simple
example that transforms a list of strings into uppercase. The example will be
in JavaScript using the imperative mindset:
var list = ["dogs", "hot dogs", "bananas"];
function upcase(list) {
var newList = [];
for (var i = 0; i < [Link]; i++) {
[Link](list[i].toUpperCase());
}
return newList;
}
• Click HERE to purchase this book now. discuss
Chapter 1. Thinking Functionally •8
upcase(list);
// => ["DOGS", "HOT DOGS", "BANANAS"]
The imperative mindset uses control flow structures like for to navigate through
each element of the list, incrementing the variable i one by one. It pushes the
new uppercased string in the newList variable. The code is verbose. The what
that needs to be done is mixed and obfuscated by boilerplate actions and
mutating values.
Let’s experiment with the declarative version in Elixir. Declarative program-
ming focuses on what is necessary, doing list navigations or repetition with
recursive functions (more about this in Chapter 4, Dive into Recursion, on
page ?):
defmodule StringList do
def upcase([]), do: []
def upcase([first | rest]), do: [[Link](first) | upcase(rest)]
end
[Link](["dogs", "hot dogs", "bananas"])
# => ["DOGS", "HOT DOGS", "BANANAS"]
The upcase result of an empty list is an empty list. When the list has items,
the result is a new list where the first string is uppercased and the rest of the
items are passed to the upcase function. We describe how the data must be,
not the actions. This way of expressing the code is possible thanks to pattern
matching. You’ll see the details about it in Chapter 3, Use Pattern Matching
to Control the Program Flow, on page ?.
The procedure of transforming a list of strings in uppercase can be simplified
using higher-order functions:
list = ["dogs", "hot dogs", "bananas"]
[Link](list, &[Link]/1)
# => ["DOGS", "HOT DOGS", "BANANAS"]
This time we are saying that we want to map a list, applying the upcase trans-
formation on each item. The map function builds a new collection using the
result of the argument function. In this declarative version, we just say what
needs to be done, and the how is abstracted for us. Today, Java, PHP, Ruby,
Python, and many other languages are embracing the declarative style. It
generates much simpler code. The important aspects of the task, the parts
that matter, are explicit.
• Click HERE to purchase this book now. discuss
Wrapping Up •9
Wrapping Up
Functional programming is a programming paradigm. A programming paradigm
consists of the rules and design principles of building software; it’s the way
of thinking about a programming language. The functional paradigm focuses
on building software using pure functions organized in a way that describes
what software must do, not how. Now, with this in mind, you are going to
learn the programming foundations in detail, from scratch. You’ll be intro-
duced to Elixir syntax at the same time you learn functional concepts, at the
right pace. Come along and turn the page.
• Click HERE to purchase this book now. discuss