Professional Documents
Culture Documents
Johan Montelius
Introduction
This is not a crash course in Erlang since there are plenty of tutorials avail-
able on the web. I will however describe the tools that you need so that you
can get a programming environment up and running. I will also list a set of
task that we will work on together. I will however take for granted that you
know some programming languages, have heard of functional programing
and that recursion is not a mystery to you.
1 Getting started
The first thing you need to do is download the Erlang SDK. This is found
at www.erlang.org and is available both as a windows binary and as source
that you can make with the usual tools available on a Unix or even MacOs
platform.
1.1 Emacs
You also need an text editor and what is better than Emacs. Download
it from www.gnu.org/software/emacs/, available both for Unix, Mac and
Windows.
You need to add the code below to your .emacs file (provided that you
have Erlang installed under C:/Program Files/). This will make sure that
the Erlang mode is loaded as soon as you open a .erl file and that you can
start an Erlang shell under Emacs etc. Change the <Ver> and <ToolsVer>
to what is right in your system. On a Linux box it will look similar but the
install directory is something like /usr/local/lib/erlang/.
(setq load-path
(cons
"C:/Program Files/erl<Ver>/lib/tools-<ToolsVer>/emacs"
load-path))
(setq erlang-root-dir
"C:/Program Files/erl<Ver>")
(setq exec-path
(cons
"C:/Program Files/erl<Ver>/bin"
exec-path))
(require ’erlang-start)
1
If everything works you should be able to start an Erlang shell inside
Emacs by M-x run-erlang (M-x is < escape > followed by x)
2 Hello World
Open a file hello.erl and write the following:
-module(hello).
-export([world/0]).
world()->
‘‘Hello world!’’.
Now open a Erlang shell, compile and load the file with the command
c(hello). and, call the fuction hello:world().. Remeber to end com-
mands in th eshell with a dot. If things work out you have sucessfully
written, compiled and executed your first Erlang program.
Find the Erlang dokumentation and read the “Getting started” section.
3 A HTTP parser
To have something to work on, something that you will use in the next
session, you should implement a HTTP parser. We will not build a complete
parser nor will we implement a server that can reply to queries (yet) but we
will do enough to understand how Erlang works and how HTTP is defined.
-module(http).
-export([parse_request/1]).
We’re only going to implement the parsing of a HTTP get request; and
avoiding some details to make life easier. Download the RFC 2616 from
www.ietf.org and follow the descriptions of a request. From the RFC we
have:
2
| request-header ; Section 5.3
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 4.3
parse_request(R0) ->
{Request, R1} = request_line(R0),
{Headers, R2} = headers(R1),
{Body, _} = message_body(R2),
{Request, Headers, Body}.
The request line is, according to the RFC, a line consisting of a method,
URI, and http version; separated by space characters and terminated by a
carriage return line feed.
The method is one of: OPTIONS, GET, HEAD etc. Since we are only inter-
ested in get requests for now it makes life easy.
Note how we now treat a string a list of integers and matches the argu-
ment with the list starting with the integers of G, E and T followed by 32
which is the ASCII value for space. After having matched the input string
with “GET ” we continue with the rest of the string R0. We find the URI
and the version and finally the carriage return and line feed that end the
request line. We then return the tuple {{get, URI, Ver}, R3}, the first
element is the parsed representation of the request line and R3 is the rest of
the string.
Next we implement the parsing of the URI. This requires recursive defi-
nitions that if you have not been exposed to logic nor functional programing
this might twist your head. If you have done some functional programming
you might say “this is not tail recursive, I can do it better”, that is fine I
only wanted to make things easy and not introduce things that we don’t
need.
3
request_uri([32|R0])->
{[], R0};
request_uri([C|R0]) ->
{Rest, R1} = request_uri(R0),
{[C|Rest], R1}.
Headers also have internal structure but we are only interested in di-
viding them up into individual strings and most important find the end of
the header section. We implement is as two recursive functions; one that
consumes a sequence of headers and one that consumes individual headers.
headers([13,10|R0]) ->
{[],R0};
headers(R0) ->
{Header, R1} = header(R0),
{Rest, R2} = headers(R1),
{[Header|Rest], R2}.
header([13,10|R0]) ->
{[], R0};
header([C|R0]) ->
{Rest, R1} = header(R0),
{[C|Rest], R1}.
The last thing we need is parsing of the body and we will make things
very easy (even cheating). We assume that the body is everything that is
left but the truth is not that simple. If we call our function with a string
as input argument there is little discussion of how large the body is but
this is not easy if we want to parse an incoming stream of bytes. When do
we reach the end, when should we stop waiting for more? The length of
the body is therefore encoded in the headers of the request. Or rather in
4
the specification of HTTP 1.0 and 1.1 there are several alternative ways of
determining the length of the body. If you dig deeper into the specs you will
find that it is quite messy. In our little world we will however treat the rest
of the string as the body.
message_body(R) ->
{R, []}.
You now have all the pieces and if you compile and load the module in a
Erlang shell you can parse a request. Call the function with the http module
prefix and give it a string to parse.
7>c(http).
{ok,http}
8>http:parse_request("GET /index.html HTTP/1.1\r\nfoo 34\r\n\r\nThis is the body").
{get,"/index.html",v11,["foo 34"],"This is the body"}
9>
4 Finding a prime
This is a test that we should use in a coming exercise. The task is to test
if a number is prime. A complete algorithm is quite expensive to execute
for large numbers so we use an algorithm that will detect if number is not
a prime with very high accuracy. The algorithm is from Fermat and to
compute it we need a fast implementation of modular exponentiation. Open
up a new file fermat.erl and declare the module fermat.
mpow(N, 1, _) ->
N;
mpow(N, K, M) ->
mpow(K rem 2, N, K, M).
mpow(0, N, K, M) ->
X = mpow(N, K div 2, M),
(X * X) rem M;
mpow(_, N, K, M) ->
X = mpow(N, K - 1, M),
(X * N) rem M.
This algorithm will calculate N K mod M either by N K/2 ∗ N K/2 mod M
if K is even, or by N K−1 ∗ N mod M if K is odd. Modular multiplication
is nice since you can apply the modular operation on both terms and the
result will be the same. Try it and see if it works.
Next we implement the test by Fermat. If a random number R, less than
P , raised to P − 1 modulo P is equal to 1 e.g. if RP −1 is relative prime to
P , then it is very likely that P is prime.
5
fermat(1) ->
ok;
fermat(P) ->
R = random:uniform(P-1),
T = mpow(R,P-1,P),
if
T == 1 ->
ok;
true ->
no
end.
Note that it is only likely so we want to perform this test with different
random numbers.
test(_, 0) ->
ok;
test(P, N) ->
case fermat(P) of
ok ->
test(P, N-1);
no ->
no
end.
How many times do we have to perform the test, well it depends on how
many false primes you want to find. If note that most numbers are not
prime and fail the test in one try. If we stumble on a prime we might as
well run the test a couple of time since it will not slow down the over all
performance that much.
That’s it. Compile, load and do some experiments. Why not build a
prime generator, start with an integer and test if it’s a prime. If it’s not
then move on to the next integer. Notice that Erlang is implemented using
a big-num packet and can handle integers of (almost) arbitrary size. This is
(probably) a prime that I found after some searching:
75654596987987976987
68756756757657656987
98789798798789796546
54654564217541236547
65421378512736521765
73658765123765123786
512378657852319179
6
5 Dijkstra
This is a algorithm that we will use when we build a network of routers.
The algorithm will compute a routing table. The table is represented by a
list with one entry per node where the entry describes which gateway should
be used to reach the node. The input to the algorithm is a map represented
as a set of vertexes and a set of gateways to which we have direct access. In
our example our own node will not be explict part of the map.
Before we implement the algorithm we need to implement operations on
a map and operations on the sorted list. Before implementing the opera-
tions I advice you to study the lists library and learn how keysearch/3,
keydelete/2, map/2 and foldl/3 works. It will make your life easier.
• all nodes(Map): lists all nodes in the map, also the one without
outgoing links.
7
• update(Node, N, Gateway, Sorted): update the list Sorted with
the information that Node can be reached in N hops using Gateway.
If the current shortest path to a node in Nodes is longer than N then
the entry in Sorted must be replaced. Use the above functions, why
does entry/2 return 0 if the node is not found?