Dmytro Lytovchenko. BEAM Wisdoms.
http://beam-wisdoms.clau.se/en/latest/
http://erlang.org/faq/introduction.html
http://whyerlang.com/
https://en.wikipedia.org/wiki/Functional_programming
Robert Virding. Hitchhiker's Tour of the BEAM
https://www.youtube.com/watch?v=_Pwlvy3zz9M
Steve Vinoski. A Peek Inside Erlang's OTP
https://www.youtube.com/watch?v=_Pwlvy3zz9M
Text
https://www.erlang.org/
Kaczmarczyk, James
Sakai, Christian
"If Java is 'write once, run anywhere', then Erlang is 'write once, run forever'"
Joe Armstrong,
creator of Erlang
http://elixir-lang.org/
# Basic syntax
defmodule Example do
def add_one_to_one do
1 + 1
end
end
iex(2)> Example.add_one_to_one()
2
Execute a function add_one_to_one that is located in module Example.
The execution returns 2 as a result
defmodule SpawnExample do
def say_hi do
IO.puts "Hello!"
end
end
iex(2)> spawn(SpawnExample, :say_hi, [])
Hello!
#PID<0.91.0>
iex(3)> spawn_link(SpawnExample, :say_hi, [])
Hello!
#PID<0.93.0>
iex(4)> spawn_monitor(SpawnExample, :say_hi, [])
Hello!
PID<0.95.0>
Spawn another process. If this spawned process dies, the spawner process stays alive and unaffected.
Spawn another process. If this spawned process dies, the spawner process also dies.
Spawn another process. If this spawned process dies, the spawner process gets notified.
defmodule MessageExample do
def listen do
receive do
{:hello_cutie, from} ->
IO.puts """
Received :hello_cutie from
#{inspect(from)},
but not going to reply back.
"""
{:please_reply, from} ->
IO.puts """
Received :please_reply from
"#{inspect(from)}",
all right, I'll reply back.
"""
send(from, :what)
{:kill_yourself, from} ->
IO.puts """
Told to kill myself from
#{inspect(from)},
fine, I'll kill myself.
"""
Process.exit(self(), :kill)
end
end
end
iex(8)> spawned_pid = spawn(MessageExample, :listen, [])
#PID<0.113.0>
iex(9)> send(spawned_pid, {:hello_cutie, self()})
Received :hello_cutie from
#PID<0.90.0>,
but not going to reply back.iex(10)> send(spawned_pid, {:please_reply, self()})
Received :please_reply
from "#PID<0.90.0>",
all right, I'll reply back.
{:please_reply, #PID<0.90.0>}
iex(11)> receive do
...(11)> :what ->
...(11)> IO.puts "Got :what back"
...(11)> end
Got :what backiex(12)> send(spawned_pid, {:kill_yourself, self()})
Told to kill myself from
#PID<0.90.0>,
fine, I'll kill myself.
{:kill_yourself, #PID<0.90.0>}
iex(13)> Process.alive?(spawned_pid)
falsedefmodule Juliet do
def listen_for_love_letter do
receive do
{:i_love_you, from} ->
send(from, :i_love_you_too)
{:lets_die_together, from} ->
Process.exit(self(), :kill)
{:do_my_math_homework, from} ->
1 / 0
end
end
enddefmodule Romeo do
def listen_for_reply do
receive do
:i_love_you_too ->
IO.puts "Yeah! she loves me too"
end
end
endiex(4)> my_pid = self()
#PID<0.96.0>
iex(5)> {juliet_pid, _} = spawn_monitor(Juliet, :listen_for_love_letter, [])
{#PID<0.106.0>, #Reference<0.0.4.146>}
iex(6)> juliet_pid
#PID<0.106.0>
iex(7)> send(juliet_pid, {:do_my_math_homework, self()})
{:do_my_math_homework, #PID<0.96.0>}
iex(8)>
18:03:10.576 [error] Process #PID<0.106.0> raised an exception
** (ArithmeticError) bad argument in arithmetic expression
process.exs:94: Juliet.listen_for_love_letter/0
nil
iex(9)> Process.alive?(juliet_pid)
false
iex(10)> Process.alive?(my_pid)
trueiex(2)> juliet_pid = spawn(Juliet, :listen_for_love_letter, [])
#PID<0.99.0>
iex(3)> send(juliet_pid, {:i_love_you, self()})
{:i_love_you, #PID<0.96.0>}
iex(4)> Romeo.listen_for_reply()
Yeah! she loves me tooiex(2)> self()
#PID<0.96.0>
iex(3)> juliet_pid = spawn_link(Juliet, :listen_for_love_letter, [])
#PID<0.100.0>
iex(4)> send(juliet_pid, {:lets_die_together, self()})
** (EXIT from #PID<0.96.0>) killedThe Erlang VM, called Beam, is more than a simple interpreter. It’s like its own little operating system running on top of your host operating system.
It handles its own events, process scheduling, memory, naming services, and interprocess communication. In addition to all that, a node can connect to other nodes— in the same computer, across a LAN, or across the Internet— and provide many of the same services across these connections that it provides to the processes it hosts locally.
defmodule Alpha do
def start do
:global.register_name(:alpha, self())
end
def do_action do
send_message()
listen_for_report()
end
def send_message do
send(:global.whereis_name(:bravo), :is_area_clear)
end
def listen_for_report do
receive do
:area_clear ->
IO.puts "All area clear"
end
end
enddefmodule Bravo do
def start do
:global.register_name(:bravo, self())
end
def do_action do
listen_for_command()
end
def listen_for_command do
receive do
:is_area_clear ->
send_message()
end
end
def send_message do
send(:global.whereis_name(:charlie), :is_area_clear)
end
end
defmodule Charlie do
def start do
:global.register_name(:charlie, self())
end
def do_action do
listen_for_command()
end
def listen_for_command do
receive do
:is_area_clear ->
send_message()
end
end
def send_message do
send(:global.whereis_name(:delta), :is_area_clear)
end
enddefmodule Delta do
def start do
:global.register_name(:delta, self())
end
def do_action do
listen_for_command()
end
def listen_for_command do
receive do
:is_area_clear ->
send_message()
end
end
def send_message do
send(:global.whereis_name(:alpha), :area_clear)
end
end⇒ iex --sname alpha alpha.exs
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(alpha@Christian-Sakais-MacBook-Pro)1> Node.connect(:"br
avo@Christian-Sakais-MacBook-Pro")
true
iex(alpha@Christian-Sakais-MacBook-Pro)2> Alpha.start
:yes
iex(alpha@Christian-Sakais-MacBook-Pro)3> Alpha.do_action()
All area clear
:ok
iex(alpha@Christian-Sakais-MacBook-Pro)4>
⇒ iex --sname bravo bravo.exs
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(bravo@Christian-Sakais-MacBook-Pro)1> Node.connect(:"ch
arlie@Christian-Sakais-MacBook-Pro")
true
iex(bravo@Christian-Sakais-MacBook-Pro)2> Bravo.start
:yes
iex(bravo@Christian-Sakais-MacBook-Pro)3> Bravo.do_action()
:is_area_clear
iex(bravo@Christian-Sakais-MacBook-Pro)4>⇒ iex --sname charlie charlie.exs
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(charlie@Christian-Sakais-MacBook-Pro)1> Node.connect(:"
delta@Christian-Sakais-MacBook-Pro")
true
iex(charlie@Christian-Sakais-MacBook-Pro)2> Charlie.start
:yes
iex(charlie@Christian-Sakais-MacBook-Pro)3> Charlie.do_action()
:is_area_clear
iex(charlie@Christian-Sakais-MacBook-Pro)4>⇒ iex --sname delta delta.exs
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(delta@Christian-Sakais-MacBook-Pro)1> Node.list
[:"charlie@Christian-Sakais-MacBook-Pro",
:"bravo@Christian-Sakais-MacBook-Pro",
:"alpha@Christian-Sakais-MacBook-Pro"]
iex(delta@Christian-Sakais-MacBook-Pro)2> Delta.start
:yes
iex(delta@Christian-Sakais-MacBook-Pro)3> Delta.do_action(
)
:area_clear
iex(delta@Christian-Sakais-MacBook-Pro)4>We call an instance of BEAM over a network, a "Node"
⇒ iex --sname boss job.exs
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(boss@Christian-Sakais-MacBook-Pro)1> Node.connect(:"worker@Christian-Sakais-MacBook-Pro")
true
iex(boss@Christian-Sakais-MacBook-Pro)2> func = fn -> IO.inspect(Node.self()) end
#Function<20.52032458/0 in :erl_eval.expr/5>
iex(boss@Christian-Sakais-MacBook-Pro)3> Node.spawn(:"worker@Christian-Sakais-MacBook-Pro", func)
:"worker@Christian-Sakais-MacBook-Pro"
#PID<12320.98.0>
iex(boss@Christian-Sakais-MacBook-Pro)4>⇒ iex --sname worker
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(worker@Christian-Sakais-MacBook-Pro)1> Node.list
[:"boss@Christian-Sakais-MacBook-Pro"]
iex(worker@Christian-Sakais-MacBook-Pro)2> self()
#PID<0.86.0>
iex(worker@Christian-Sakais-MacBook-Pro)3>
Send a local function to be invoked in other Node
⇒ iex --sname boss
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(boss@Christian-Sakais-MacBook-Pro)1> Node.connect(:"worker@Christian-Sakais-MacBook-Pro")
true
iex(boss@Christian-Sakais-MacBook-Pro)2> Node.spawn(:"worker@Christian-Sakais-MacBook-Pro", Job, :work, [])
#PID<8967.95.0>
Boss told me, #PID<0.95.0>, to do work
iex(boss@Christian-Sakais-MacBook-Pro)3>⇒ iex --sname worker job.exs
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(worker@Christian-Sakais-MacBook-Pro)1>Tell other Node to execute its function
defmodule Job do
def work do
IO.puts "Boss told me, #{inspect self()}, to do work"
end
end