Contemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptx
Introduction to Erlang
1. An Introduction to Erlang
Corrado Santoro
Dipartimento di Matematica e Informatica
Universita’ di Catania
Master Cloud P.A.
Corrado Santoro An Introduction to Erlang
2. Overview
1 Erlang Basics:
Function programming principles
Basic syntax
Basic recursion and list usage
2 Data types, Matching and Advanced Recursion:
Variables and assignment principles
Erlang data types
Using tail-recursion
Corrado Santoro An Introduction to Erlang
3. The Erlang Language
Definition
Erlang is a functional language developed by Ericsson for
provide a flexible and safe support to program
telecommunication equipments.
Characteristics
Functional Semantics
Strong usage of lists
Concurrent programming model based on isolated
processes exchanging messages
Runtime support for the creation of distributed and highly
fault-tolerant applications.
It can be downloaded from http://www.erlang.org
Corrado Santoro An Introduction to Erlang
4. Erlang and Functional Programming
Functional Programming
A program is a set of functions, similar to algebraic
functions, which behave by working only on input values and
giving output results.
Strict analogy with algebra, this we don’t have:
global variables
for and while constructs, we use recursion
if and case constructs, we use multiple function clause
Corrado Santoro An Introduction to Erlang
5. Our first function: factorial
The mathematical formulation
0! = 1
n! = n · (n − 1)! , ∀n > 0
This definition does not contain either cycles for or if
statements.
Can we implement it exactly “as is”?
Corrado Santoro An Introduction to Erlang
6. Our first function: factorial
Solutions in C:
✞
int fact (int n) {
if (n == 0)
return 1;
else
return n * fact (n - 1);
}
✡✝ ✆
✞
int fact (int n) {
int res = 1;
while (n > 1) {
res = res * n;
n --;
}
return res;
}
✡✝ ✆
Corrado Santoro An Introduction to Erlang
7. Our first function: factorial
Solutions in C:
✞
int fact (int n) {
if (n == 0)
return 1;
else
return n * fact (n - 1);
}
✡✝ ✆
✞
int fact (int n) {
int res = 1;
while (n > 1) {
res = res * n;
n --;
}
return res;
}
✡✝ ✆
Solution in Erlang:
✞
fact(0) -> 1;
fact(N) -> N * fact(N - 1).
✡✝ ✆
Mathematical formulation
0! = 1
n! = n · (n − 1)! , ∀n > 0
Corrado Santoro An Introduction to Erlang
8. Erlang: first syntactical elements
✞
fact(0) -> 1;
fact(N) -> N * fact(N - 1).
✡✝ ✆
fact Function name; it is defined using two clauses
fact(0) -> 1; First clause executed when the
argument is “0”.
The definition is terminated with symbol “;”, it means that
other clauses will follow.
fact(N) -> N * fact(N - 1). Second clause
executed when the condition on the first clause is not met
(that is the argument is not “0”).
The definition ends with symbol “.” meaning that this is the
last clause of the function.
Corrado Santoro An Introduction to Erlang
9. Erlang: first syntactical elements
✞
fact(0) -> 1;
fact(N) -> N * fact(N - 1).
✡✝ ✆
Function names and language keywords are literal
symbols starting with lowercase.
Variables and Parameter are literal symbols starting with
uppercase.
Symbol “->” separates function definition from function
body (implementation).
Function/clause body contains a set of expressions,
comma-separated, which are evaluated in sequence.
The value of the last expression is the return value of the
function (or clause).
Corrado Santoro An Introduction to Erlang
10. Guards
✞
fact(0) -> 1;
fact(N) -> N * fact(N - 1).
✡✝ ✆
What does it happen if we invoke fact(-3)?
✞
fact(-3) = -3 * fact (-4)
fact(-3) = -3 * (-4 * fact (-5))
fact(-3) = -3 * (-4 * (-5 * fact (-6)))
...
✡✝ ✆
The execution does not terminate!
Indeed, the program has an error since the value of factorial is
not defined when n < 0.
This check is not present in our program!
Corrado Santoro An Introduction to Erlang
11. Guards
Let’s take a look at the mathematical formulation
0! = 1
n! = n · (n − 1)! , ∀n > 0
We must add the condition N > 0.
✞
fact(0) -> 1;
fact(N) when N > 0 -> N * fact(N - 1).
✡✝ ✆
The statement “when + boolean expression” after function (or
clause) declaration is called guard.
A guard activates the clause if and only if the boolean
expression evaluates true.
Corrado Santoro An Introduction to Erlang
12. Guards
✞
fact(0) -> 1;
fact(N) when N > 0 -> N * fact(N - 1).
✡✝ ✆
First clause is activated when argument is 0.
Second clause is true when the argument is > 0.
What about fact(-3)?
No clause is met and a run-time error (exception) is raised
“undefined function clause”.
That’s really our aim! A program crash is expected since
the function is not defined for negative arguments.
Corrado Santoro An Introduction to Erlang
13. An Exercise
Sum of the first N even numbers
sumpair(0) = 0
sumpair(n) = n + sumpair(n − 2) , ∀n > 0 , even
sumpair(n) = sumpair(n − 1) , ∀n > 0 , odd
✞
sumpair(0) -> 0;
sumpair(N) when ((N rem 2) == 0) and (N > 0) ->
N + sumpair(N - 2);
sumpair(N) when N > 0 -> sumpair(N - 1).
✡✝ ✆
Corrado Santoro An Introduction to Erlang
14. Lists
An Erlang list is an ordered set of any Erlang term.
It is syntactical expressed as a comma-separated set of
elements, delimited with “[” and “]”.
Example: [7, 9, 15, 44].
“Roughly speaking”, a list is a C array.
However it’s not possible to directly get the i-th element, but we
can separate the first element from the tail of the list.
Using only this operation, the complete manipulation of a list is
possible!
Corrado Santoro An Introduction to Erlang
15. Lists: separation operator
[ First | Rest ] = List.
First will contain the first element of the list.
Rest will contain the sublist of the element starting from the
second till the end.
Corrado Santoro An Introduction to Erlang
16. Lists: Examples
[ First | Rest ] = [7, 9, 15, 44].
First = 7
Rest = [9, 15, 44]
[ Head | Tail ] = [16].
Head = 16
Tail = []
[ First | Tail ] = [].
runtime error! It is not possible to get the first element
from an empty list.
Corrado Santoro An Introduction to Erlang
17. Example: sum of all elements of a list
Mathematical formulation
sum([x1, . . . , xn]) =
n
i=1
xi
C Implementation:
✞
int sum (int * x, int n) {
int i, res = 0;
for (i = 0;i < n;i++)
res += x[i];
return res;
}
✡✝ ✆
Erlang does not have the construct to get the i-th element, nor
the for. We must use recursion!
Corrado Santoro An Introduction to Erlang
18. Example: sum of all elements of a list
Mathematical formulation with recursion
sum([]) = 0
sum([x1, x2, . . . , xn]) = x1 + sum([x2, . . . , xn])
Let’s do it in Erlang:
✞
sum([]) -> 0;
sum([ Head | Tail ]) -> Head + sum(Tail).
%% sum(L) -> [ Head | Tail ] = L, Head + sum(Tail).
✡✝ ✆
C solution uses 6 lines of code and 2 local variables.
Erlang solution uses only 2 lines of code!
Corrado Santoro An Introduction to Erlang
19. List Construction
Operator “|” is also used to build a list.
List = [ FirstElement | TailOfTheList ].
It builds a list by chaining the element FirstElement at with
the list TailOfTheList.
Corrado Santoro An Introduction to Erlang
20. List Construction: Examples
X = [7 | Y].
Y = [9, 15, 44]
X = [7, 9, 15, 44]
X = [Y | Z].
X = 16 e Z = []
X = [16]
X = [Y | [1, 2, 3]].
X = 16
X = [16, 1, 2, 3]
Corrado Santoro An Introduction to Erlang
21. Example: double each element of a list
C solution:✞
void doubling (int * x, int n) {
int i;
for (i = 0;i < n;i++) x[i] *= 2;
}
✡✝ ✆
Erlang solution:
✞
doubling([]) -> [];
doubling([ Head | Tail ]) -> [Head * 2 | doubling (Tail)].
✡✝ ✆
Corrado Santoro An Introduction to Erlang
22. Example: filtering a list
Let’s write a function that, given a list L, returns a new list
containing only the elements of L greater than 10.
Solution 1:✞
filter([]) -> [];
filter([ Head | Tail ]) when Head > 10 ->
[Head | filter (Tail)];
filter([ Head | Tail ]) -> filter (Tail).
✡✝ ✆
Corrado Santoro An Introduction to Erlang
23. Filtering an array in C
Can we do the same thing in C?
Yes but... a couple of problems:
We have to return a new array.
We must allocate the new array before filling it.
But we don’t know in advance the size of this resulting
array.
What do we have to do?
Corrado Santoro An Introduction to Erlang
24. Array filtering in C
✞
int * filter (int * x, int n, int * newN) {
int i, j, newSize = 0;
int * result;
/* first, let’s compute the size of the resulting array */
for (i = 0;i < n;i++)
if (x[i] > 10) newSize ++;
/* then let’s allocate the resulting array */
result = malloc (newSize * sizeof (int));
/* finally let’s fill the array */
for (i = 0, j = 0; i < n;i++) {
if (x[i] > 10) {
result[j] = x[i];
j++;
}
}
*newN = newSize;
return result;
}
✡✝ ✆
“Some more lines” w.r.t. Erlang solution.
Corrado Santoro An Introduction to Erlang
25. Quicksort
The algorithm is quite simple:
1 Starting from a list, we get a cutting element.
2 Two sublists are built: the first contains all elements less
than the cutting element; the second list contains the
elements greater than the cutting element.
3 Steps 1 and 2 are recursively applied to the two sublists.
4 Sublist 1, cutting element and sublist 2 are chained
together.
Corrado Santoro An Introduction to Erlang
26. Quicksort: a numerical example
4 21 43 2 1 9 33 10 8
Corrado Santoro An Introduction to Erlang
27. Quicksort: a numerical example
4 21 43 2 1 9 33 10 8
2 1 4 21 43 9 33 10 8
Corrado Santoro An Introduction to Erlang
28. Quicksort: a numerical example
4 21 43 2 1 9 33 10 8
2 1 4 21 43 9 33 10 8
1 2 4 21 43 9 33 10 8
Corrado Santoro An Introduction to Erlang
33. Quicksort: implementation
Mathematical formulation
quicksort([ ]) = [ ]
quicksort([x1, x2, . . . , xn]) = quicksort([xi : xi ∈ [x2, . . . , xn], xi < x1]) ⊕
⊕ [x1] ⊕
⊕ quicksort([xi : xi ∈ [x2, . . . , xn], xi >= x1])
✞
quicksort([]) -> [];
quicksort([X1 | L]) ->
quicksort([X || X <- L, X < X1]) ++ [X1] ++
quicksort([X || X <- L, X >= X1]).
✡✝ ✆
Here we used the Erlang operator “++” to concatenate two lists.
Corrado Santoro An Introduction to Erlang
34. Part II
Data types, Matching and Advanced Recursion
Corrado Santoro An Introduction to Erlang
35. Assignment
1 As in classical programming languages, Erlang supports
variables
2 They can “assigned” by using the symbol “=” which
however has the meaning of match
3 As in mathematics, the “=” symbol does not really mean
“assignment” but that the LHS and RHS are the same
(equal)!
4 Thus the sequence has the following meaning:
A = 3, variable A has not assigned before (it is unbound),
the statement succeeds by assigning 3 to A
A = A + 1, since variable A is now bound, this statement
has the meaning 3 = 3 + 1, which is false!
The statement above thus generates a bad match
exception.
Corrado Santoro An Introduction to Erlang
36. Assignment
A bound variable cannot be thus reused as in classical
imperative language
This seems weird but has some precise reasons:
1 The symbol “=” has its own mathematical meaning: equal!
2 This semantics makes pattern matching very easy
Example: Ensuring that the first two elements of a list are the
same:
✞
[H, H | T ] = MyList
✡✝ ✆
Corrado Santoro An Introduction to Erlang
37. The “list member” function
Matching is very useful in function clause heads
Let’s implement a function which checks if an element
belongs to the list
✞
member(X, []) -> false;
member(X, [X | T]) -> true;
member(X, [H | T]) -> member(X, T).
✡✝ ✆
The code above may be rewritten in a more elegant way by
using the “ ” symbol which means “don’t care”
✞
member(_, []) -> false;
member(X, [X | _]) -> true;
member(X, [_ | T]) -> member(X, T).
✡✝ ✆
Corrado Santoro An Introduction to Erlang
38. A step behind: overview of Erlang data types
Integers, the are “big-int”, i.e. integers with no limit
Reals, usually represented in floating-point
atoms, Symbolic constants made of literals starting with
lowercase. Example: hello, ciao, thisIsAnAtom.
They are atomic entities; even if they are literals, they
cannot be treated as “classical” C or Java strings. Instead,
they play the role of symbolic constants (like C #define
or Java final).
tuples, ordered sequences of elements representing, in
general, a structured data.
Examples: {item, 10}, {15, 20.3, 33},
{x, y, 33, [1, 2, 3]}.
The number of elements is fixed at creation time and
cannot be changed. They are something like C structs.
lists
Corrado Santoro An Introduction to Erlang
39. Optimising Erlang: tail recursion
Let’s go back to the factorial:
✞
fact(0) -> 1;
fact(N) -> N * fact(N - 1).
✡✝ ✆
It works but has a big problem: recursive function calls create,
each time, an activation frame in the stack, thus causing its
growth.
In order to avoid it, tail recursion and accumulators can be
used:
✞
fact(N) -> fact(N, 1).
fact(0, Acc) -> Acc;
fact(N, Acc) -> Acc1 = Acc * N, fact(N - 1, Acc1).
✡✝ ✆
Corrado Santoro An Introduction to Erlang
40. Optimising Erlang: tail recursion
✞
fact(N) -> fact(N, 1).
fact(0, Acc) -> Acc;
fact(N, Acc) -> Acc1 = Acc * N, fact(N - 1, Acc1).
✡✝ ✆
If the last statement of a clause is a recursive call; and
The recursive call is not included in a mathematical
expression; then
The function is tail recursive and recursion is not
performed using a subroutine call but a go to (i.e. it always
uses the same activation frame)
Corrado Santoro An Introduction to Erlang
41. Summing list elements with tail recursion
Not tail recursive:
✞
sum([]) -> 0;
sum([ Head | Tail ]) -> Head + sum(Tail).
✡✝ ✆
Tail recursive:
✞
sum(L) -> sum(L, 0).
sum([], Acc) -> Acc;
sum([ Head | Tail ], Acc) -> sum(Tail, Head + Acc).
✡✝ ✆
Corrado Santoro An Introduction to Erlang
42. Part III
A Sample Module: Property Lists (or Dictionaries)
Corrado Santoro An Introduction to Erlang
43. Dictionaries
Let us implement a module which handles a dictionary with data in
the form:
[{key1, value1}, {key2, value2}, ... ]
Exports:
new()→[]
insert(Dict, Key, Value)→NewDict
delete(Dict, Key)→NewDict
member(Dict, Key)→bool
find(Dict, Key)→{ok, Value} | error
Corrado Santoro An Introduction to Erlang
44. Dictionary
✞
-module(dictionary).
-export([new/0, insert/3, delete/2, member/2, find/2]).
new() -> [].
member([], _Key) -> false;
member([{Key, _Value} | _Tail], Key) -> true;
member([ _ | Tail], Key) -> member(Tail, Key).
insert(Dict, Key, Value) ->
M = member(Dict, Key),
if
M -> % The key exists
Dict;
true -> % The key does not exist
[{Key, Value} | Dict]
end.
✡✝ ✆
Corrado Santoro An Introduction to Erlang
45. The “if” construct
The source code above uses the “if” erlang statement, which has a
semantics and a syntactical construction quite different than that of
imperative languages:
if
cond1− >expr1 ;
cond2− >expr2 ;
....
condn− >exprn ;
true− >expr true
end
Conditions may be different and not related to the same
variables;
However conditions can use only variables and boolean
expression but not function invocation;
Corrado Santoro An Introduction to Erlang
46. The “case” construct
The “case” erlang statement does not suffer of the limitations of the
“if” and has a semantics and a syntactical construction quite similar to
that of imperative languages:
case expr1 of
val1− >expr1 ;
val2− >expr2 ;
....
valn− >exprn ;
− >expr default
end
Conditions may be different and not related to the same
variables;
It is more like a case statement.
Corrado Santoro An Introduction to Erlang
47. Dictionary
✞
-module(dictionary).
-export([new/0, insert/3, delete/2, member/2, find/2]).
new() -> [].
member([], _Key) -> false;
member([{Key, _Value} | _Tail], Key) -> true;
member([ _ | Tail], Key) -> member(Tail, Key).
insert(Dict, Key, Value) ->
case member(Dict, Key) of
true -> % The key exists
Dict;
false -> % The key does not exist
[{Key, Value} | Dict]
end.
✡✝ ✆
Corrado Santoro An Introduction to Erlang
49. Strings
An Erlang string is a list in which each element is the ASCII code of
the n-th character:
The string Hello can be expressed in erlang as:
"Hello"
[72,101,108,108,111]
[$H,$e,$l,$l,$o]
The literal $car is a short-cut for “ASCII code of character car”.
A string can be manipulated as a list:
[Head | Tail] = "Hello"
Head = 72
Tail = "ello"
Corrado Santoro An Introduction to Erlang
50. Exercise on strings and lists
Write a function:
split(String, SepChar) → [Token1, Token2, ...]
which separates a string into tokens (returns a list of string) on the
basis of the separation char SepChar.
Corrado Santoro An Introduction to Erlang
53. Concurrency in Erlang
Traditional approach: pthread
Different execution units sharing data and exploiting
synchronization mechanisms for concurrency control
(semaphores, mutexes, condition variables).
Erlang approach: message passing
Concurrent processes totally separated which share nothing
and interact only with message passing.
Corrado Santoro An Introduction to Erlang
54. COPL: Concurrency-Oriented Programming
Languages
According to Joe Armstrong’s definition, the COPLs avoid the
semantic gap between a concurrent problem and its
implementation.
Given a problem:
1 identify the concurrent activities.
2 identify the information flow among concurrent activities.
3 implement activities with processes and information with
messages.
No data sharing: no need for (complex) synchronization
constructs, the model features transparency w.r.t. location, in
a distributed environment.
Corrado Santoro An Introduction to Erlang
55. Erlang Statements for Concurrency
Process creation:
spawn (ModuleName, FunctionName, ListOfParameters).
It returns an Erlang Pid identifying the process.
Sending a message (bang operator):
PID ! DataToSend
{NetworkNode,PID} ! DataToSend
Message reception:
Data = receive X -> X end
Corrado Santoro An Introduction to Erlang
56. A very simple concurrent program
Let’s write a function that spawns a process, sends a data and
gets back a reply.
✞
-module(ping_pong).
-export([caller/0, responder/0]).
caller() ->
Pid = spawn(ping_pong, responder, []),
Pid ! {self(), 100},
receive
Reply -> ok
end.
responder() ->
receive
{From, Data} ->
From ! Data + 1
end.
✡✝ ✆
Corrado Santoro An Introduction to Erlang
57. A more complex concurrent program
Parallel Factorial (version for one master + two workers):
let’s compute N!
First worker computes products from 2 to |N
2 | and sends back
result to master.
Second worker computes products from |N
2 | + 1 to N and sends
back result to master.
Master multiples the two partial results.
Corrado Santoro An Introduction to Erlang
59. Exercise: Parallel Factorial with “m” workers
Let’s compute N!
The interval [2, N] is subdivided into “m” subintervals.
Each worker computes the sub-product of its sub-interval and
sends back result to master.
Master multiples all the partial results.
1 Compute each subinterval [Ai, Bi ];
2 Spawn the m processes and gather the PIDs into a list;
3 Scan the list and wait, for each PID, the result; gather the
result into a list;
4 Multiply all the results together and return the final number.
Corrado Santoro An Introduction to Erlang
60. Processes with States
Let us suppose we need, in a Erlang program, a memory
database storing tuples in the form {Key, Value}.
Such a DB must be live and shared by any Erlang process,
so cannot propagate the DB itself in a varaible.
We must use a process holding the DB and handling a
proper set of messsage for interaction with the world.
Messages will correspond to functionalities such as:
Add a new tuple
Get all tuples
Search for a tuple given the key
Delete a tuple given the key
...
Each message will be handled in a client/server fashion.
Corrado Santoro An Introduction to Erlang
61. The DB (Part 1)
✞
-module(db).
-export([start/0, db_loop/1, add/3, getall/1, get/2]).
start() ->
spawn(db, db_loop, [ [] ]).
db_loop(TheDB) ->
receive
{From, add, Key, Value} ->
case lists:keymember(Key, 1, TheDB) of
true -> % the key exists returns an error
From ! duplicate_key,
db_loop(TheDB);
false -> % the key does not exist, add it
From ! ok,
db_loop( [ {Key, Value} | TheDB ])
end;
{From, getall} ->
From ! TheDB,
db_loop(TheDB);
{From, get, Key} ->
case lists:keyfind(Key, 1, TheDB) of
false -> % key not found
From ! not_found;
{K, V} ->
From ! {K, V}
end,
db_loop(TheDB)
end.
...
✡✝ ✆
Corrado Santoro An Introduction to Erlang
64. Distributed Erlang Systems
An Erlang distributed system is composed of a set of erlang
nodes.
An Erlang Node is characterised by:
A live erlang virtual machine
A fully qualified node name, made of a user-defined part
and the IP address/name of the host, in the form
’name@IP’ (it is an atom)
A cookie, i.e. a specific data which must be the same in all
nodes of the system and is used for security reasons.
Corrado Santoro An Introduction to Erlang
65. Distributed Ping-pong
Let’s write a ping-pong program working in distributed Erlang.
✞
-module(d_ping_pong).
-export([start_responder/0, responder/0, ping/2, stop/1]).
start_responder() ->
Pid = spawn(d_ping_pong, responder, []),
register(responder, Pid).
responder() ->
receive
{From, Data} ->
From ! Data + 1,
responder();
bye ->
ok
end.
ping(Node, Data) ->
{responder, Node} ! {self(), Data},
receive
Reply -> Reply
end.
stop(Node) ->
{responder, Node} ! bye.
✡✝ ✆
Corrado Santoro An Introduction to Erlang
68. Linked Processes
If a process is created using the spawn link function, an
internal link is created between the creating and the
created processes.
Links have a specific role during process termination and
are used in fault handling
Links also work in distributed Erlang and can be also made
between processes belonging to different nodes.
The link function can be used to make a link to an
already existing process.
Corrado Santoro An Introduction to Erlang
69. Linked Processes: Normal Termination
If a process normally terminates, nothing happens to
linked processes
Corrado Santoro An Introduction to Erlang
70. Linked Processes: Termination with Errors
If a process terminates with an error, but ...
... linked processes do not trap exit signal (normal
behaviour), then
linked processes will terminate as well (cascade
termination).
Corrado Santoro An Introduction to Erlang
71. Linked Processes: Termination with Errors
If a process terminates with an error, and ...
... linked processes (proc2) issued a call to
process flag(trap exit, true), then
linked processes will receive an EXIT message than can
be handled properly.
Corrado Santoro An Introduction to Erlang
72. Linked Processes: an Example
✞
-module(test_link).
-export([start/0, one/0, two/0, stop/0]).
start() ->
Pid = spawn(test_link, one, []),
register(one, Pid).
one() ->
Pid = spawn_link(test_link, two, []),
register(two, Pid),
one_loop().
one_loop() ->
io:format("Onen"),
receive
bye ->
ok % exit(normal) or exit(error)
after 1000 ->
one_loop()
end.
...
✡✝ ✆
Corrado Santoro An Introduction to Erlang
73. Linked Processes: an Example (2)
✞
...
two() ->
%process_flag(trap_exit,true),
two_loop().
two_loop() ->
io:format("Twon"),
receive
Msg ->
io:format("Received ˜pn", [Msg])
after 1000 ->
two_loop()
end.
stop() ->
one ! bye.
✡✝ ✆
Corrado Santoro An Introduction to Erlang
74. An Example: A supervisor
Let us write a simple supervisor
It manages a list of processes to be controlled, given in the
form: {Pid, Module, Function, Arguments}
Each time a processes crashes, the supervisor performs a
restart
Two API functions are given:
add(M, F, A), adds a new process given the module, the
function and the arguments;
get proc list(), returns the list of running processes
managed by the supervisor.
Corrado Santoro An Introduction to Erlang
81. Erlang Common Process Models
An Erlang system is a set of interacting processes
The way in which such processes interact is often conform
to few precise models:
client/server: the process waits for a request message,
handles it and sends a reply;
one way: the process waits for a request message,
handles it but does not send any reply;
finite-state-machine: the process evolves according to a
finite-state machine in which events are the reception of
specific messages and/or timeouts;
Corrado Santoro An Introduction to Erlang
82. Erlang Common Process Models
In general, the code of an Erlang module handling a
process is composed of the following parts:
A “start” function which spawns the process by running
its intialization function;
An initialization function which perform process startup
operation and then runs the main message reception loop;
A message handler, it is in general the same process loop
function, which waits for a message, recognises it, executes
the proper operations, sends the reply (if needed), and
re-enters the loop;
A process state, made of a piece of information which is
passed through the main loop function (with updates if
needed);
An API, made of some functions which interacts with the
process by sending the proper messages.
Corrado Santoro An Introduction to Erlang
83. The Message Handler of a Process
A message handler
waits for a message;
parses the message (a message is in general composed by
a From field and some specific parts which depend by the
functionality carried by the message);
handles the message by executing the proper code;
sends a reply (if needed)
Parts in blue are generic and common to all source codes
for Erlang processes
Parts in red are specific for each kind of Erlang process
The Erlang/OTP platform provides ready-to-use
behaviours, which are library modules implementing the
generic part, and they are designed for implementing
well-defined process patterns
Corrado Santoro An Introduction to Erlang
84. gen server
gen server is a module for the implementation of
processes behaving according to the client/server pattern
The programmer has to write API function and callback
functions to handle the messages (specific parts)
The part regarding message reception, parsing and reply
sending is managed directly by the module
The module also supports the protocol for the
interoperability with supervisors, for the implementation of
fault-tolerant systems.
Corrado Santoro An Introduction to Erlang
86. Starting a gen server
A gen server is started through a call to one of the functions:
start(Module, Args, Options) − > Result
start link(Module, Args, Options) − > Result
start(ServerName, Module, Args, Options) − >
Result
start link(ServerName, Module, Args,
Options) − > Result
Here:
Module is the name of the callback module
Args is the list of arguments to be passed to the init
callback function
ServerName is the name of the process, if it has to be
registered
Options are some process-specific options
The reply is {ok, Pid} or {error, ErrorReason}
Corrado Santoro An Introduction to Erlang
87. Starting a gen server
As a result, the callback function Module:init(Args) is
called, whose result can be
{ok, State}
{ok, State, Timeout}
{stop, Reason}
Corrado Santoro An Introduction to Erlang
88. The Database Example with gen server
✞
-module(database).
%% this module implements a gen_server behaviour
-behaviour(gen_server).
-export([start/0, init/1, .... ]).
start() ->
%% Module is ’database’ (the same),
%% No arguments
%% No options
gen_server:start_link(database, [], []).
init(Args) ->
{ok, []}. %% start with an empty database
✡✝ ✆
Corrado Santoro An Introduction to Erlang
89. Managing calls in a gen server
To call a gen server “service” one of the following functions can
be used:
call(Pid, Request) − > Reply
call(Pid, Request, Timeout) − > Reply
Here:
Pid is the process pid or name
Request is an Erlang term which represents the request
Timeout is an optional timeout value, in milliseconds
Corrado Santoro An Introduction to Erlang
90. Managing calls in a gen server
As a result, the callback function
Module:handle call(Request, From, State) is called,
where
Request is the request
From is the sender process
State is the server process state
The result of the callback can be:
{reply,Reply,NewState}, a reply is sent and a new
process state is set
{stop,Reason,Reply, NewState}, a reply is sent, but
the server is going to be stopped
Corrado Santoro An Introduction to Erlang
91. The Database Example with gen server
✞
-module(database).
-behaviour(gen_server).
-export([start/0, add/3, getall/1, get/2, init/1, handle_call/3]).
start() ->
gen_server:start_link(database, [], []).
%% -------------------------------------------------------------------------------
%% API
%% -------------------------------------------------------------------------------
add(Pid, K, V) -> gen_server:call(Pid, {add, K, V}).
getall(Pid) -> gen_server:call(Pid, {getall}).
get(Pid, Key) -> gen_server:call(Pid, {get, Key}).
...
✡✝ ✆
Corrado Santoro An Introduction to Erlang
92. The Database Example with gen server
✞
...
%% -------------------------------------------------------------------------------
%% CALLBACKS
%% -------------------------------------------------------------------------------
init(Args) -> {ok, []}. %% start with an empty database
handle_call({add, Key, Value}, _From, TheDB) ->
case lists:keymember(Key, 1, TheDB) of
true -> % the key exists returns an error
{reply, duplicate_key, TheDB};
false -> % the key does not exist, add it
{reply, ok, [ {Key, Value} | TheDB ]}
end;
handle_call({getall}, _From, TheDB) -> {reply, TheDB, TheDB};
handle_call({get, Key},_From, TheDB) ->
case lists:keyfind(Key, 1, TheDB) of
false -> % key not found
{reply, not_found, TheDB};
{K, V} ->
{reply, {K, V}, TheDB}
end.
✡✝ ✆
Corrado Santoro An Introduction to Erlang
94. gen event
gen server is a module for the implementation of
processes behaving as a finite-state machine
Example, a fixed-phone line fsm (from Cesarini,
Thompson, “Erlang Programming”):
Corrado Santoro An Introduction to Erlang
95. Starting a gen fsm
A gen fsm is started through a call to one of the functions:
start(Module, Args, Options) − > Result
start link(Module, Args, Options) − > Result
start(ServerName, Module, Args, Options) − >
Result
start link(ServerName, Module, Args,
Options) − > Result
Here:
Module is the name of the callback module
Args is the list of arguments to be passed to the init
callback function
ServerName is the name of the process, if it has to be
registered
Options are some process-specific options
The reply is {ok, Pid} or {error, ErrorReason}
Corrado Santoro An Introduction to Erlang
96. Starting a gen fsm
As a result, the callback function Module:init(Args) is
called, whose result can be
{ok, StateName, StateData}
{ok, StateName, StateData, Timeout}
{stop, Reason}
StateName is an atom which represents the state of the fsm
StateData is the process data
Corrado Santoro An Introduction to Erlang
97. Handling Events a gen fsm
To generate an event, the following function is used:
send event(Pid, Event) − > ok
Here:
Pid is the process pid or name
Event is an atom which represents the event
As a result, the callback function Module:StateName(Event,
StateData) is called, where
StateName is the state handling the event
Event is the event to be handled
StateData is the server process state
The result of the callback can be:
{next state, NextStateName, NextStateData}
{next state, NextStateName, NextStateData,
TimeoutVal}
Corrado Santoro An Introduction to Erlang
98. The gen fsm of the fixed-line phone
✞
-module(phone).
-behaviour(gen_fsm).
-export([start/0,
incoming/0, off_hook/0, on_hook/0, other_on_hook/0, connect/0,
init/1,
idle/2, ringing/2, connected/2, dial/2]).
-define(SERVER_NAME, phone).
start() ->
gen_fsm:start_link({local, ?SERVER_NAME}, ?MODULE, [], []).
%% -------------------------------------------------------------------------------
%% API
%% -------------------------------------------------------------------------------
incoming() -> gen_fsm:send_event(?SERVER_NAME, incoming).
off_hook() -> gen_fsm:send_event(?SERVER_NAME, off_hook).
on_hook() -> gen_fsm:send_event(?SERVER_NAME, on_hook).
other_on_hook() -> gen_fsm:send_event(?SERVER_NAME, other_on_hook).
connect() -> gen_fsm:send_event(?SERVER_NAME, connect).
...
✡✝ ✆
Corrado Santoro An Introduction to Erlang
99. The gen fsm of the fixed-line phone
✞
...
%% -------------------------------------------------------------------------------
%% CALLBACKS
%% -------------------------------------------------------------------------------
init(Args) -> {ok, idle, []}.
idle(incoming, StateData) ->
io:format("Incoming calln"),
{next_state, ringing, StateData};
idle(off_hook, StateData) ->
io:format("The user is making a calln"),
{next_state, dialing, StateData}.
ringing(other_on_hook, StateData) ->
io:format("The peer closed the calln"),
{next_state, idle, StateData};
ringing(off_hook, StateData) ->
io:format("We answered the calln"),
{next_state, connected, StateData}.
connected(on_hook, StateData) ->
io:format("The call terminatedn"),
{next_state, idle, StateData}.
dial(on_hook, StateData) ->
io:format("The call terminatedn"),
{next_state, idle, StateData};
dial(connect, StateData) ->
io:format("The peer answered the calln"),
{next_state, connected, StateData}.
✡✝ ✆
Corrado Santoro An Introduction to Erlang
100. Supervisors
The Erlang library provides a library module for the
implementation of supervisors
A supervisor can monitor processes compliant to OTP and thus
implemented as gen server, gen fsm or gen event.
A supervisor needs a callback module which has the task of:
Performing initialization tasks, if needed
Specifying which are the children processes and their
restart policy
Corrado Santoro An Introduction to Erlang
101. Starting a supervisor
A supervisor is started through a call to one of the functions:
start link(Module, Args, Options) − > Result
start link(ServerName, Module, Args,
Options) − > Result
Here:
Module is the name of the callback module
Args is the list of arguments to be passed to the init
callback function
ServerName is the name of the process, if it has to be
registered
Options are some process-specific options
The reply is {ok, Pid} or {error, ErrorReason}
Corrado Santoro An Introduction to Erlang
102. Starting a supervisor
As a result, the callback function Module:init(Args) is
called, whose result can be
{ok, SupervisorSpecification,
ChildSpecificationList}
SupervisorSpecification is a tuple specifying restart
policy
ChildSpecificationList is the list of children processes
Corrado Santoro An Introduction to Erlang
103. Starting a supervisor
SupervisorSpecification = {RestartStrategy,
AllowedRestarts, MaxSeconds}
RestartStrategy:
one for one, the crashed child is restarted
one for all, if a child crahses, all children are terminated
and restarted
rest for one, if a child X crahses, all children are started
after X will be terminated and restarted
AllowedRestarts is the maximum number of abnormal
termination allowed in MaxSeconds seconds; these two
parameters specify the maximum abnormal termination/restart
frequency.
Corrado Santoro An Introduction to Erlang
104. Starting a supervisor
ChildSpecificationList = [{Id, {Mod, Fun, Args},
Restart, Shutdown, Type, ModuleList}]
Id, an id (atom) assigned to the child
{Mod, Fun, Args}, the specification of starting function of the
child module, with its args
Restart is the restart policy which can be transient,
temporary or permanent
Shutdown is the maximum time allowed between a termination
command and the execution of terminate function
Type is the process type, it can be worker or supervisor
ModuleList is the list of modules implementing the process;
this information is used during a software upgrade
Corrado Santoro An Introduction to Erlang
106. An Introduction to Erlang
Corrado Santoro
Dipartimento di Matematica e Informatica
Universita’ di Catania
Master Cloud P.A.
Corrado Santoro An Introduction to Erlang