Introduction to Erlang
Franck Petit / Sebastien Tixeuil Firstname.Lastname@lip6.fr
Hello World
•
‘%’ starts a comment•
‘.’ ends a declaration•
Every function must be in a module•
one module per source file•
source file name is module name + “.erl”•
‘:’ used for calling functions in other modulesRecursive Functions
•
Variables start with upper-case characters•
‘;’ separates function clauses•
‘,’ separates instructions•
Variables are local to the function clause•
Pattern matching and guards to select clausesRecursive Functions
-module(mymath).
-export([factorial/1]).
factorial(0) -> 1;
factorial(N) ->
N * factorial(N-1).
> mymath:factorial(6).
720
Tail Recursion
•
The arity is part of the function name•
Non-exported functions are local to the moduleTail Recursion
-module(mylists).
-export([reverse/1]).
reverse(L) ->
reverse(L, []).
reverse([H|T], L) ->
reverse(T, [H|L]);
reverse([], L) ->
L.
> mylists:reverse([3,2,1]).
[1,2,3]
Recursion over Lists
•
Pattern-matching selects components of the data•
‘_’ is a “don’t care” pattern (not a variable)•
‘[]’ is the empty list•
‘[X,Y,Z]’ is a list with exactly three elements•
‘[X,Y,Z|Tail]’ has three or more elementsList Recursion with Accumulator
•
The same syntax is used to construct lists•
Strings are simply lists of character codes•
Avoid adding data to the end of the listNumbers
•
Regular numbers123 -34567 12.345 -27.45e-05
•
#-notation for base-N integers 16#ffff•
$-notation for character codes (ISO-8859-1)$A (->65)
Atoms
•
Must start with lower case character or be quoted fridayunquoted_atoms_cannot_contain_blanks
’A quoted atom with several blanks’
’hello \n my friend’
•
Similar to hashed strings•
use only one word of data•
constant-time equality testTuples
•
Terms separated by ‘,’ and enclosed in {}{a,12,’hello’}
{1,2,{3, 4},{a,{b,c}}}
{}
•
A fixed number of items (similar to structure or record in conventional programming languages)•
A tuple whose first element is an atom is called a tagged tupleOther Data Types
•
Functions•
Binaries•
Process identifiers•
References•
No separate booleans•
Erlang values in general are called “terms”•
All terms are ordered and can be compared with ‘<‘, ‘>’, ‘==’, ‘=:=’, etc.Built-in Functions
•
Implemented in C•
All the type tests and conversions are BIFs•
Most BIFs (not all) are in the module “erlang”•
Many common BIFs are auto-imported (recognized without writing “erlang:...”)•
Operators (‘+’,’-’,’*’,’/’,...) are also really BIFsStandard Libraries
•
Application Libraries•
Kernel•
erlang•
code•
file•
inet•
os•
Stdlib•
lists•
dict•
sets•
...Expressions
•
Boolean and/or/xor are strict (always evaluate both arguments)•
Use andalso/orelse for short circuit evaluation•
‘==’ for equality, not ‘=’•
Always use parentheses when not absolutely certain about the precedenceFun Expressions
•
Anonymous functions (lambda expressions)•
Can have several clauses•
All variables in the pattern are new•
All variable bindings in the fun are local•
Variables bound in the environment can be used in the fun-bodyPattern Matching
•
Match failure causes run-time error•
Successful matching binds the variables•
but only if they are not already bound to a value•
previously bound variables can be used in a pattern•
a new variable can also be repeated in a patternPattern Matching
mylength([]) ->
0;
mylength([_|T]) ->
mylength(T) + 1.
Case-switches
•
Any number of clauses•
Patterns and guards, just as in functions•
‘;’ separates clauses•
Use ‘_’ as catch-all•
Variables may also begin with underscore•
signals “I don’t intend to use this value”If-switches
•
Like a case-switch without the patterns and the‘when’ keyword
•
Use ‘true’ as catch-allfactorial(N) when N == 0 -> 1;
factorial(N) when N > 0 ->
! N * factorial(N - 1).
Switching
• Pattern Matching
factorial(0) -> 1;
factorial(N) ->
N * factorial(N-1).
• When
factorial(N) when N == 0 -> 1;
factorial(N) when N > 0 ->
! N * factorial(N - 1).
• If
factorial(N) ->
if
N == 0 -> 1;
N > 0 -> N * factorial(N - 1) end.
• Case
factorial(N) -> 1 case (N) of
0 -> 1;
N when N > 0 -> N * factorial(N - 1) end.
List Processing
•
List Processing BIFsatom_to_list(A) float_to_list(F)
integer_to_list(I) tuple_to_list(T)
list_to_atom(L) ...
hd(L) tl(L)
length(L)
•
List Processing Functions member(X,L)append(L1,L2) reverse(L)
delete_all(X,L)
Tuple Processing
•
Tuple Processing BIFs tuple_to_list(T) element(N,T)setelement(N,T,Val) size(L)
...
•
Multiple Return Values•
PID, now()...Catching Exceptions
•
throw: user defined•
error: runtime errors•
exit: end process•
only catch throw exceptions normallyProcesses
•
Code is executed by a process•
A process keeps track of the programpointer, the stack, the variables values, etc.
•
Every process has a unique process identifier•
Processes are concurrentProcesses:
Implementation
•
Virtual machine layer processes•
Preemptive multitasking•
Little overhead (e.g. 100.000 processes)•
Can use multiple CPUs on multiprocessor machinesConcurrency
•
Several processes may use the same program code at the same time•
each has own program counter, stack, and variables•
programmer need not think about other processes updating the variablesMessage Passing
•
“!” is the send operator•
Pid of the receiver is used as the address•
Messages are sent asynchronously•
The sender continues immediately•
Any value can be sent as a messageEcho
-module(echo).
-export([start/0,loop/0]).
start() ->
spawn(echo, loop, []).
loop() ->
receive {From, Message} ->
io:format("> echo: ~w Msg: ~w ~n", [self(), Message]), From ! Message,
loop() end.
> Id=echo:start(), Id ! {self(),hello}.
echo: <0.35.0> Msg: hello {<0.32.0>,hello}
>
Message Queues
•
Each process has a message queue (mailbox)•
incoming messages are placed in the queue (no size limit)•
A process receives a message when it extracts it from the mailbox•
need not take the first message in the queueReceiving a Message
•
receive-expressions are similar to case switches•
patterns are used to match messages in the mailbox•
messages in the queue are tested in order•
only one message can be extracted each timeSelective Receive
•
Patterns and guards permit message selection•
receive-clauses are tried in order•
If no message matches, the process suspends and waits for a new messageReceive with Timeout
•
A receive-expression can have an after-part•
can be an integer (milliseconds) or“infinity”
•
The process waits until a matching message arrives, or the timeout limit is exceeded•
soft real-time: no guaranteesSend and Reply
•
Pids are often included in messages (self()), so that the receiver can reply to the sender•
If the reply includes the Pid of the second process, it is easier for the first processto recognize the reply
Message Order
•
The only guaranteed message order iswhen both the sender and the receiver are the same for both messages (first-in, first- out)
Selecting Unordered Messages
•
Using selective receive, it is possible tochoose which messages to accept, even if they arrive in a different order
Starting Processes
•
The “spawn” function creates a new process•
The new process will run the specified function•
The spawn operation always returns immediately•
The return value is the Pid of the “child”Process Termination
•
A process terminates when:•
it finishes the function call that it started with•
there is an exception that is not caught•
All messages sent to a terminated process will be thrown away•
Same Pid will not be used before long timeA Stateful Server
•
The parameter variables of a server loop can be used to remember the current stateHot Code Swapping
•
When using “module:function(...)”, the latest version of module is always used•
If the server module is recompiled and reloaded, the process will jump to the new code after handling the nextmessage
Registered Processes
•
A process can be registered under a name•
Any process can send a message to a registered process, or look up the Pid•
The Pid might change (if the process is restarted and re-registered), but the name stays the samePid = spawn(?MODULE, server, []), register(myserver, Pid),
myserver ! Msg.
Links and Exit Signals
•
Any two processes can be linked•
Links are always bidirectionnal•
When a process dies, an exit signal is sent to all linked processes, which are also killed•
normal exit does not kill other processesTrapping Exit Signals
•
If a process sets its trap_exit flag, all signals will be caught and turned into normalmessages
•
process_flag(trap_exit, true)•
{‘EXIT’, Pid, ErrorTerm}•
This way, a process can watch other processesDistribution
•
Running “erl” with the flag “-name xxx”•
starts the Erlang network distribution system•
makes the virtual machine emulator a“node” (‘xxx@host.domain’)