An introduction to
@sbfrr
le Wagon alumni batch #2
Running on the BEAM
- scalable
- fault-tolerant
- distributed
- non-stop
Inspired from Ruby
defmodule Math do
def sum(a, b) do
a + b
end
end
class Math
def sum(a, b)
a + B
end
end
What's going to happen ?
- iex == pry
- pair programming
- learning by doing
http://elixir-lang.org/docs/stable/elixir/Kernel.html
and h is your friend inside of iex ;)
How to deal with the compiler ?
First option
> iex
> c("my_elixir_file.ex")
> MyModule.my_function()
Second option
> elixir "my_elixir_file.ex"
Need HELP ?
> h Module
> h Module.function
> h Module.function/arity
Try it yourself ! It's fun !
LANGUAGE PRIMITIVES
Data Types
- Integer => 1
- Float => 1.0
- Atom => :atom
- Booleans => true / false
- List => [1, 2, 3]
- Tuple => {1, 2, 3}
- String => "string"
- Function => fn() -> "hello" end
- Keyword List => [a: "a"] == [{:a, "a"}]
Assignment
# Reassignment
a = 1 # 1
a = 2 # 2
# Underscore Variable
_ = Do.something("with", "this")
# Assignment and Mathematical Equal
a = [1, 2] # [1, 2]
[1, 2] = a # [1, 2]
[2, 3] = a # ???? Try it ! It's fun as well ;)
# What about that ?
[1, a] = [2, 3]
# And that ?
[a|_] = [1, 2]
Tuples or Lists ?
# Lists
iex> [head|tail] = [1, 2, 3]
[1, 2, 3]
iex> 1 = head
1
iex> [2, 3] = tail
[2, 3]
iex> list = [1 | [2 | [3 | []]]]
[1, 2, 3]
iex> [0 | list]
[0, 1, 2, 3]
# Tuples
iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> elem(tuple, 1)
"hello"
Pattern Matching
iex> 1 = x
1
iex> 2 = x
** (MatchError) no match of right hand side value: 1
iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}
iex> a
:hello
iex> b
"world"
iex> {a, b, c} = {:hello, "world"}
** (MatchError) no match of right hand side value: {:hello, "world"}
Module and Functions
defmodule BasicMath do
def add(x, y) do
x + y
end
def add_square(x, y) do
square(x) + square(y)
end
defp square(x) do
x * x
end
end
BasicMath.add_square(2,2) # 8
Functions and Pattern Matching
defmodule Say do
def hello("world") do
"No way, I can't say hello world anymore!"
end
def hello(name) do
"Hello " <> name
end
end
Say.hello("world") #"No way, I can't say hello world anymore!"
Say.hello("John Doe") #"Hello John Doe"
In Case of...
defmodule Say do
def hello(name) do
case name do
"world" ->
"No way, I can't say hello world anymore!"
_ ->
"Hello " <> name
end
end
end
Say.hello("world") #"No way, I can't say hello world anymore!"
Say.hello("John Doe") #"Hello John Doe"
Pattern Loop Matching
defmodule LoopOver do
def this_list([]), do: IO.puts "DONE"
def this_list([head|tail]) do
IO.puts head
this_list(tail)
end
end
LoopOver.this_list([1, 2, 3])
YOUR TURN !!!
WRITE AN IMPLEMENTATION OF THE FIBONACCI SERIES IN ELIXIR
GO GO GO !!!
A (NAIVE) IMPLEMENTATION
#saved as test_module.ex
defmodule TestModule do
def fib(0), do: 0
def fib(1), do: 1
def fib(n), do: fib(n-1) + fib(n-2)
end
#### Uses in iex
# TestModule.fib(0) #=> 0
# TestModule.fib(1) #=> 1
# TestModule.fib(10) #=> 55
# TestModule.fib(-10) #=> this will hang as it will recurse for infinite time
Object vs. Process
Let's get into the real shit !
Remember
First option
> iex
> c("my_elixir_file.ex")
> MyModule.my_function()
Second option
> elixir "my_elixir_file.ex"
Third option
> iex -r "my/file/path.ex"
Need HELP ?
> h Module
> h Module.function
> h Module.function/arity
Elixir uses the actor model of concurrency.
An actor is an independent process that shares nothing with any other process.
You can spawn new processes, send them messages, and receive messages back.
And that’s it (apart from some details about error handling and monitoring).
from "Programming Elixir"
What is a process ?
iex> pid = spawn fn -> 1 + 2 end
#PID<0.44.0>
iex> Process.alive?(pid)
false
iex> self()
iex> Process.alive?(self())
# Let's take the opportunity to introduce the pipe operator
iex> self() |> Process.alive?
Sending and receiving messages
iex> self |> send({:hello, "world"})
{:hello, "world"}
iex> receive do
...> {:hello, msg} -> msg
...> end
"world"
Let's CODE !!!
Pattern matching and messages
iex> send self(), {:hello, "world"}
{:hello, "world"}
iex> receive do
...> {:hello, msg} -> msg
...> {:world, msg} -> "won't match"
...> end
"world"
Let's CODE !!
Links
iex> spawn fn -> raise "oops" end
#PID<0.58.0>
iex> spawn_link fn -> raise "oops" end
#PID<0.41.0>
Let's CODE !!
A Key/Value Store
defmodule KV do
def start_link do
Task.start_link(fn -> loop(%{}) end)
end
defp loop(map) do
receive do
{:get, key, caller} ->
send caller, Map.get(map, key)
loop(map)
{:put, key, value} ->
loop(Map.put(map, key, value))
end
end
end
Naming a Process
iex(2)> Process.register(pid, Project.Worker)
true
iex(3)> pid = Process.whereis(Project.Worker)
#PID<0.93.0>
Your turn
What about two process playing PING/PONG ?
Can you code it ?
Inspired by
-
http://elixir-lang.org/getting-started/introduction.html
- http://blog.songsaboutsnow.com
- Programming Elixir Book
Would you like some more ?
OTP ? PHOENIX ?
Just name it ;)
THANKS
@sbfrr
le Wagon alumni batch #2
An introduction to Elixir
By sbfrr
An introduction to Elixir
Presentation for le Wagon Meetup: Elixir Up and Running
- 990