Introduction to Elixir
Functional Programming
Immutable Data
iex(1)> list = [1,2,3,4]
[1, 2, 3, 4]
iex(2)> List.delete(list, 2)
[1, 3, 4]
iex(3)> list
[1, 2, 3, 4]
iex(4)> list = List.delete(list, 2)
[1, 3, 4]
iex(5)> list
[1, 3, 4]
So, no Side-Effects, and no such a thing like...

Functions Everywhere
Based on Erlang
Actor Model
Handles High Concurrency




Ready to Fault-tolerance
Hot code swap
Ready to easy distribution
OTP
And how does it look like?
Basic Types
Numbers
10
1_000
-10
10.5
...
Booleans
true
false
Atoms
:one
:two
:hello
Strings
iex> x = "hello"
iex> x <> " world"
"hello world"
iex> "#{x} world"
"hello world"
Binaries
iex> <<0, 1, 2, 3>>
<<0, 1, 2, 3>>
iex(1)> "hello" <> <<1>>
<<104, 101, 108, 108, 111, 1>>
iex(2)>
iex(1)> <<104, 101, 108, 108, x>> = "hello"
"hello"
iex(2)> x
111
Anonymous functions
iex> add = fn a, b -> a + b end
#Function<12.71889879/2 in :erl_eval.expr/5>
iex> add.(2, 2)
4
Collections
Lists
iex> [1, 2, true, 3]
[1, 2, true, 3]
Tuples
iex> {:ok, "hello"}
{:ok, "hello"}
Key-value lists/Dictionaries
Keymaps
iex> list = [{:a, 1}, {:b, 2}]
[a: 1, b: 2]
iex> list == [a: 1, b: 2]
true
Giving an example of use...
query = from w in Weather,
where: w.prcp > 0,
where: w.temp < 20,
select: w
Maps
iex> map = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}
iex> map[:a]
1
Structs
Structs
iex(2)> defmodule Person do
...(2)> defstruct [:name, :age]
...(2)> end
{:module, Person,
<<70, 79, 82, 49, 0, 0, 8, 248, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 186,
131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115,
95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>, %Person{age: nil, name: nil}}
iex(3)> no_one = %Person{}
%Person{age: nil, name: nil}
iex(4)> me = %Person{name: "Kleber", age: 26}
%Person{age: 26, name: "Kleber"}
iex(5)>
Pattern Matching
Pattern Matching
iex(6)> a = 1
1
iex(7)> 1 = a
1
iex(8)> 2 = a
** (MatchError) no match of right hand side value: 1
iex(9)> {1, a} = {2, 3}
** (MatchError) no match of right hand side value: {2, 3}
iex(9)> {1, a} = {1, 3}
{1, 3}
iex(10)> a
3
iex(11)> "helllo" <> <<1>>
<<104, 101, 108, 108, 108, 111, 1>>
iex(12)> <<104, 101, 108, 108, x>> = "hello"
"hello"
iex(13)> x
111
Using in function arguments
defmodule Person do
defstruct [:name, :blood_type]
end
defmodule BloodTypeDonation do
def receive_donation(%Person{blood_type: "a"}) do
# do things specific for the blood type A
end
def receive_donation(%Person{blood_type: "b"}) do
# do things specific for the blood type B
end
end
Processes
Spawning Processes
iex(6)> spawn fn -> IO.inspect(self()) end
#PID<0.96.0>
#PID<0.96.0>
iex(7)> IO.inspect(self())
#PID<0.83.0>
#PID<0.83.0>
Linking Processes

Linking Processes
iex(3)> spawn fn -> raise "Godzilla attacked and you were not able to notify anyone, you died in vein" end
#PID<0.109.0>
09:54:15.386 [error] Process #PID<0.109.0> raised an exception
** (RuntimeError) Godzilla attacked and you were not able to notify anyone, you died in vein
:erlang.apply/2
iex(4)> spawn_link fn -> raise "Godzilla attacked, but you notified someone above you, you're now a hero =](but a dead one =[)" end
09:55:36.756 [error] Process #PID<0.111.0> raised an exception
** (RuntimeError) Godzilla attacked, but you notified someone above you, you're now a hero =](but a dead one =[)
:erlang.apply/2
** (EXIT from #PID<0.105.0>) an exception was raised:
** (RuntimeError) Godzilla attacked, but you notified someone above you, you're now a hero =](but a dead one =[)
:erlang.apply/2
OTP
Supervisors

Supervisors
defmodule MySupervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, :ok)
end
def init(:ok) do
children = [
worker(MySupervisionedModule, [])
]
supervise(children, strategy: :one_for_one)
end
end
defmodule MySupervisionedModule do
def start_link do
# Do something ...
end
end
GenServers
GenServers
defmodule SumServer do
use GenServer
def handle_call(:get, _caller_pid, number) do
{:reply, number, number/2}
end
def handle_cast({:sum, number_to_sum}, current_value) do
new_value = current_value + number_to_sum
{:noreply, new_value}
end
end
iex(29)> {:ok, pid} = GenServer.start_link(SumServer, 0)
{:ok, #PID<0.272.0>}
iex(30)> GenServer.call(pid, :get)
0
iex(31)> GenServer.cast(pid, {:sum, 10})
:ok
iex(32)> GenServer.call(pid, :get)
10.0
iex(33)> GenServer.call(pid, :get)
5.0
And some Elixir abstractions over OTP
Agents
Agents
iex(47)> {:ok, agent} = Agent.start_link fn -> 10 end
{:ok, #PID<0.298.0>}
iex(48)> Agent.update(agent, fn current -> current + 10 end)
:ok
iex(49)> Agent.get(agent, fn current -> current end)
20
Tasks
Tasks
iex(7)> counter = fn() -> for n <- 1..5, do: IO.puts n end
#Function<20.52032458/0 in :erl_eval.expr/5>
iex(8)> Task.async counter
1
2
3
4
5
%Task{owner: #PID<0.108.0>, pid: #PID<0.120.0>, ref: #Reference<0.0.3.1006>}
iex(7)> task = Task.async(fn() -> Enum.reduce(1..10, fn(x,y) -> x + y end) end)
%Task{owner: #PID<0.87.0>, pid: #PID<0.101.0>, ref: #Reference<0.0.1.523>}
iex(8)> IO.puts Task.await(task)
55
:ok
Tasks
defmodule Talker do
def talk_alone() do
IO.puts "hello world!"
:timer.sleep 500
IO.puts "I SAID: HELLO....WORLD!"
:timer.sleep 5
IO.puts "OK, I GIVE UP"
end
end
iex(11)> Task.async &Talker.talk_alone/0
hello world!
%Task{owner: #PID<0.87.0>, pid: #PID<0.126.0>, ref: #Reference<0.0.1.973>}
I SAID: HELLO....WORLD!
OK, I GIVE UP

introduction-elixir
By Kleber Nascimento Gueriero
introduction-elixir
- 938