Você está na página 1de 25

Sequential Erlang

Conditional evaluation
!

Erlang has three different ways to do conditional


evaluation
!
!
!

Pattern matching the same that we have been using when we


define functions
Case Construct
If construct

Case construct (1)


!
!
!
!
!

The case construct depends on the pattern matching to select


the expression that must be executed
First at all, the expression associate to the case construct is
evaluated
Depending what the result is, a specific case is selected
Each case in the case clause is separated by a semicolon (;)
The general form is:
case conditional-expression of
Pattern1 -> expression1, expression2, .. ;
Pattern2 -> expression1, expression2, .. ;
... ;
Patternn -> expression1, expression2, ..
end

Case construct (2)


Because Erlang is a functional language, the case construct
is in reality an expression and its execution must return a
value
! All the possible cases must be covered, if not, an
execution error can be produced
! We can include a clause that catches everything, but this
clause is against the Erlang philosophy (let it to crash)
! Case expressions can be nested
!

Case construct example


invierte2(Lst) ->
case Lst of
[] -> [];
[H | T] -> invierte2(T) ++ [H]
end.

factorial(X,K) ->
case X of
0 -> K(1);
X -> factorial(X-1,(fun (X1) -> K(X * X1) end))
end.

The scope of variables in Erlang case


construct
The scope of a variable is defined as the region where the
variable can be used
! The same variable name can be used in different regions
of a program
! Depending on the case, a variable name can reference the
same variable or not
!

The if constructor (1)


The if constructor is syntactically similar to the case
constructor but it does not include the expression which
appears in the case clause (and clearly neither the key
word "of")
! The general form of the if construct is:
!

if
Guard1 -> expression11, expression12, .. ;
Guard2 -> expression21, expression22, .. ;
... ;
Guardn -> expressionn1, expressionn2, ..
end

The if constructor (2)


The guards (if they are present) are evaluate each at a
time until one of them is true and as consequence, the
body of this clause is evaluated
! If neither of the guards in the if construct is evaluated as
true, an error is raised
! With a strong use of other programming languages, we
are tempted to abuse the usage of the if construct, but if
it is possible, try to avoid its use
!

Examples
Which of the following examples show a good practice
in the use of if construct
mayor(X) ->
if
X > 0 -> mayorAcero;
X < 0 -> menorACero;
true -> igualACero
end.
if
X rem 2 == 1 -> odd;
X rem 2 == 0 -> even
end

case X rem 2 of
1 -> odd;
0 -> even
end

The use of guards in a function


The guards are additional constraints that can be part of a
function definition
! The guards are specified just before the -> sign
! The guard consist of the "when" keyword and after that,
an expression
! The function body will be evaluated if neither of the
guards before this are evaluated as true and if the own
guard is evaluated as true
!

Rewriting the factorial function using


guards

factorial(N) when N > 0 ->


N * factorial(N - 1);
factorial(0) -> 1.

Rules to write guards (1)


!

Only use:
!
!
!
!
!
!

bounded variables
literals (constant values)
predicates to test value types
terms comparison like ==, =/=, <, >, etc.
arithmetic expressions
boolean expressions (using and, or, not, xor, etc., operators)

You can NOT use:


!

user defined functions, in this way secondary effects are


avoided

Rules to write guards (2)


To express conjunctions ("and" logical operator), we can
use comma (,)
! In a similar way, it is possible to use the semicolon (;) to
express disjunctions ("or" logical operator)
! However, try to avoid the use of both operators because
it is source of confusion
!

Examples of guards

even(X) when X rem 2 == 0 -> true;


even(X) when X rem 2 == 1 -> false.

About BIFs (Built-In Functions)


All the BIFSs are defined inside the Erlang module
! Not all the functions in the Erlang module are
automatically imported, therefore, for some of them we
have to use the import attribute or to use the erlang
prefix:
!

hash(Term,Range), display(Term) are examples of these kind of functions

Some BIFs
BIF

Description

hd/1

Returns the first elemento of a list

tl/1

Returns the tail of a list

length/1

Returns the number of elements of a list

tuple_size/1

Returns the number of elements of a tuple

element/2

Returns the nth element of a tuple

setelement/3

Returns a new tuple with the same contents


of the original tuple, but replacing its nth
element with the value in argument

append_element/2

Returns a new tuple with the same contents


of the original tuple, but appending a new
element at the end of it

BIF use examples


1> List = [one,two,three,four,five].
[one,two,three,four,five]
2> hd(List).
one
3> tl(List).
[two,three,four,five]
4> length(List).
5
5> hd(tl(List)).
two
6> Tuple = {1,2,3,4,5}.
{1,2,3,4,5}
7> tuple_size(Tuple).
5
8> element(2, Tuple).
2
9> setelement(3, Tuple, three).
{1,2,three,4,5}
10> erlang:append_element(Tuple, 6).
{1,2,3,4,5,6}

Data types conversion


!

There exists some BIFs that allows us to convert a value


type into another value type

Functions

Description

atom_to_list/1, list_to_atom/1,
list_to_existing_atom/1

Convert atoms to strings and vice versa. The


list_to_existing_atom function will fail if the atom in
question has not been defined in the current session of
Erlang

list_to_tuple/1, tuple_to_list/1

Converts a tuple to a list and vice versa

float/1, list_to_float/1

Creates a float number using an integer or a string (list)

float_to_list/1, integer_to_list/1

Conversion of a number (float or integer) to a string

round/1, trunc/1, list_to_integer/1 Conversion to an integer number from a string or a


float

Conversion examples
1> atom_to_list(monday).
"monday"
2> list_to_existing_atom("tuesday").
** exception error: bad argument
in function list_to_existing_atom/1
called as list_to_existing_atom("tuesday")
3> list_to_existing_atom("monday").
monday
4> list_to_tuple(tuple_to_list({one,two,three})).
{one,two,three}
5> float(1).
1.00000
6> round(10.5).
11
7> trunc(10.5).
10

The processing of dictionaries


According to the book authors, the dictionaries (keyvalue collections) are considered a bad practice of
programming in Erlang because the retrieval and
manipulation of these values unfortunately introduces
global variables into Erlang
! There exist several functions that support the creation
and manipulation of dictionaries
! Use dictionaries but in a carefully way
!

Some functions included in the dict module

Function

Description

new() -> dictionary()

Build a dictionary

size(Dict) -> int()

Returns the number of key-value pairs inside a


dictionary

store(Key,Value, Dict1) -> Dict2

Returns a new dictionary appending a new keyvalue pair (or replacing the key-value pair, if it
exists)

fetch(Key, Dict) -> Value

Returns the value associated to a key in a


dictionary

from_list(List) -> Dict

Take a list of key-value tuples and creates a new


dictionary

Meta-programming
The ability of a function to decide what other functions
must be called in runtime is known as meta-programming
! Programs that create other programs and then execute
them
! The apply/3 function (module, function, arguments (a list))
allows us to evaluate a function inside a module with the
arguments established
!

System information BIFs

Function

Description

date/0

Returns current date {Year,Month,Day}

time/0

Returns current time {Hour,Minute,Second}

now/0

Returns the number of seconds since January, 1st of


1970 ({Megaseconds, Seconds, Microseconds}). Because
time is unique, this function can be used to generate
identifiers

Exercises (1)
!

Write an Erlang function that receives a list and a


predicate and returns a new list with the elements of the
input list that satisfy the predicate
!
!
!
!

Normal recursion
Tail recursion
CPS recursion
foldr version

Write an Erlang function that receives two input lists and


it creates the cartesian product of the two lists (4
versions)

Exercises (2)
!

!
!

It is very convenient to have functions with only one


parameter- One function f that has n paramaters can be
transformed into a function f' that has one parameter and
when it is called, it returns a function with n-1 parameters (the
rest of the parameters or the missing parameters)
In the same way, this function with n-1 parameters can be
transformed in a function with one parameter that when is
called it returns a function with n-2 parameters an so on
Write an Erlang function (curry 2) that receives a function of
two parameters and returns its curried version
How can you generalize this function?

Você também pode gostar