Sequential Erlang by Marcos Benevides
:ID: f0da3356-3797-4ddc-8306-cd333f159754
The basic constructs of the Erlang language.
Datatypes
Integers
- Large Integers are converted to
bignums
If you need to do calculations on integers using a base other than 10, you can use Base#Value notation. (Laurent 2017, 7)
Floats
- When you divide two integers with
/
, the result is automatically converted to a floating-point number. - Integer division is handled by
div
andrem
.
Atoms
- In Erlang, atoms are used to represent constant values.
- Atoms are also global, and this is achieved without the use of macro definitions or include files.
Tuples
- Represents a collection of elements (of any type) that are grouped together.
- Access is normally done by position.
- A tuple whose first element is an atom is called a
tagged
tuple, i.e.,{book, "The Aleph"}
.
Tuples are created automatically when we declare them and are destroyed when they can no longer be used. Erlang uses a garbage collector to reclaim all unused memory, so we don’t have to worry about memory allocation. (Armstrong 2013, 35)
You can also pattern match tuples by using free variables:
1> Point = {point, 10, 45}.
{point,10,45}
2> {point, X, Y} = Point.
{point,10,45}
3> X.
10
4> Y.
45
Lists
- A list is a compound data type with a variable number of terms:
[Term1,...,TermN]
. - Access is normally done by parttern matching.
- One can add or iterate over lists with the
cons
operator|
, which breaks a list intoH|T
(head
andtail
),
List = [ Element | List ] OR []
List Comprehensions
1> L = [1,2,3,4,5,6,7].
[1,2,3,4,5,6,7]
2> [ 2*X || X <- L ].
[2,4,6,8,10,12,14]
3>
The most general form of a list comprehension is an expression of the following form:
[X || Qualifier1, Qualifier2, ...]
, whereX
is an arbitrary expression, and each qualifier is either a generator, a bitstring generator, or a filter.
- Generators are written as
Pattern <- ListExpr
whereListExpr
must be an expression that evaluates to a list of terms.- Bitstring generators are written as
BitStringPattern <= BitStringExpr
whereBitStringExpr
must be an expression that evaluates to a bitstring.- Filters are either predicates or boolean expressions. (Armstrong 2013, 61)
Strings
Strictly speaking, there are no strings in Erlang. To represent a string in Erlang, we can choose between representing the string as a list of integers or as a binary. When a string is represented as a list of integers, each element in the list represents a Unicode codepoint.
To print a unicode string one must use the “t” modifier applied to the “s” control character in a formatting string, it accepts all Unicode codepoints and expect binaries to be in UTF-8:
1> X = "a\x{221e}b".
[97,8734,98]
2> io:format("~ts~n",[X]).
a∞b
ok
Records
(…) records provide a convenient way for associating a tag with each of the elements in a tuple. This allows us to refer to an element of a tuple by name and not by position. A pre-compiler takes the record definition and replaces it with the appropriate tuple reference. (Armstrong 2013)
-record(todo, {status=reminder,who=joe,text}).
to load a record from the the shell, one must use the rr
command:
1> rr("records.hrl").
[todo]
2> #todo{}.
#todo{status = reminder,who = joe,text = undefined}
3> X1 = #todo{status=urgent, text="Fix errata in book"}.
#todo{status = urgent,who = joe,text = "Fix errata in book"}
4> X2 = X1#todo{status=done}.
#todo{status = done,who = joe,text = "Fix errata in book"}
Maps
Maps are associative collections of key-value pairs.
1> TaskPending = #{ status => pending, description => 'feed cats' }.
#{status => pending,description => 'feed cats'}
2> TaskDone = TaskPending#{ status := done }.
#{status => done,description => 'feed cats'}
Identifiers
Pids
Ports
References
Variables
Note that Erlang variables start with uppercase characters. So,
X
,This
, andA_long_name
are all variables. Names beginning with lowercase letters—for example,monday
orfriday
are not variables but are symbolic constants called atoms. (Armstrong 2013)
- Erlang Variables Do Not Vary
- The scope of a variable is the lexical unit in which it is defined.
- Variables acquire values as the result of a successful pattern matching
operation (
=
).
Pattern Matching
Pattern matching is used for:
- Assigning values to variables
- Redirecting execution flows
case and if Expressions
case Expression of
Pattern1 [when Guard1] -> Expr_seq1;
Pattern2 [when Guard2] -> Expr_seq2;
...
end
if
Guard1 -> Expr_seq1;
Guard2 -> Expr_seq2;
...
end
Functions
Built-in Functions
- Conventionally, these are part of the
erlang
module. - Mostly written in C for fast execution.
List of BiFs
date()
time()
length(List)
size(Tuple)
atom_to_list(Atom)
list_to_tuple(List)
integer_to_list(1000)
tuple_to_list(Tuple)
Funs: The Basic Unit of Abstraction
Funs
are function closures. Funs
are created by expressions of the form: fun(...) -> ... end
.
Defining Your Own Control Abstractions
If we want additional control structures, we can make our own. Erlang has no for loop, so let’s make one:
for(Max, Max, F) -> [F(Max)];
for(I, Max, F) -> [F(I)|for(I+1, Max, F)].
Recursion
Tail Recursion
Guards
Modules
Defining Modules
-module(drop).
-export([fall_velocity/1, mps_to_mph/1, mps_to_kph/1]).
fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).
mps_to_mph(Mps) -> 2.23693629 * Mps.
mps_to_kph(Mps) -> 3.6 * Mps.
Error Handling in Sequential Programs
try FuncOrExpressionSeq of
Pattern1 [when Guard1] -> Expressions1;
Pattern2 [when Guard2] -> Expressions2;
...
catch
ExceptionType1: ExPattern1 [when ExGuard1] -> ExExpressions1;
ExceptionType2: ExPattern2 [when ExGuard2] -> ExExpressions2;
...
after
AfterExpressions
end
exit/1
- Used to terminate the current process.
throw
- Used as a documentation to the caller, to show that a function might throw this exception.
- error
- Crashing errors.
Fail Fast and Noisily, Fail Politely
In Erlang, when an error is detected internally by the system or is detected by program logic, the correct approach is to crash immediately and generate a meaningful error message.
(…)
Second, fail politely means that only the programmer should see the detailed error messages produced when a program crashes. A user of the program should never see these messages.