aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/getting_started
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/getting_started')
-rw-r--r--system/doc/getting_started/Makefile100
-rw-r--r--system/doc/getting_started/book.xml43
-rw-r--r--system/doc/getting_started/conc_prog.xml894
-rw-r--r--system/doc/getting_started/intro.xml66
-rw-r--r--system/doc/getting_started/make.dep14
-rw-r--r--system/doc/getting_started/part.xml36
-rw-r--r--system/doc/getting_started/records_macros.xml328
-rw-r--r--system/doc/getting_started/robustness.xml483
-rw-r--r--system/doc/getting_started/seq_prog.xml1231
-rw-r--r--system/doc/getting_started/xmlfiles.mk24
10 files changed, 3219 insertions, 0 deletions
diff --git a/system/doc/getting_started/Makefile b/system/doc/getting_started/Makefile
new file mode 100644
index 0000000000..5ca885d56e
--- /dev/null
+++ b/system/doc/getting_started/Makefile
@@ -0,0 +1,100 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include $(ERL_TOP)/erts/vsn.mk
+#VSN=$(SYSTEM_VSN)
+
+APPLICATION=otp-system-documentation
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/doc/getting_started
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+XML_PART_FILES = part.xml
+
+include xmlfiles.mk
+
+XML_CHAPTER_FILES = $(GETTING_STARTED_CHAPTER_FILES)
+
+TOPDOCDIR=..
+
+BOOK_FILES = book.xml
+
+GIF_FILES =
+
+PS_FILES = $(GIF_FILES:%.gif=%.ps)
+
+XML_FILES = \
+ $(BOOK_FILES) $(XML_CHAPTER_FILES) \
+ $(XML_PART_FILES)
+# ----------------------------------------------------
+
+HTML_FILES = \
+ $(XML_PART_FILES:%.xml=%.html)
+
+HTMLDIR = ../html/getting_started
+
+
+HTML_UG_FILE = $(HTMLDIR)/users_guide.html
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+DVIPS_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+docs: html
+
+local_docs: PDFDIR=../../pdf
+
+html: $(GIF_FILES) $(HTML_UG_FILE)
+
+debug opt:
+
+clean clean_docs:
+ rm -rf $(HTMLDIR)
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f errs core *~
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_docs_spec: docs
+# $(INSTALL_DIR) $(RELEASE_PATH)/pdf
+# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \
+ $(RELSYSDIR)
+
+release_spec:
diff --git a/system/doc/getting_started/book.xml b/system/doc/getting_started/book.xml
new file mode 100644
index 0000000000..c256dc1317
--- /dev/null
+++ b/system/doc/getting_started/book.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Getting Started with Erlang</title>
+ <prepared>Mike Williams</prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>book.sgml</file>
+ </header>
+ <insidecover>
+ </insidecover>
+ <pagetext>Getting Started with Erlang</pagetext>
+ <preamble>
+ <contents level="2"></contents>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="part.xml"/>
+ </parts>
+ <listofterms></listofterms>
+ <index></index>
+</book>
+
diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml
new file mode 100644
index 0000000000..34ae428b2c
--- /dev/null
+++ b/system/doc/getting_started/conc_prog.xml
@@ -0,0 +1,894 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Concurrent Programming</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>conc_prog.xml</file>
+ </header>
+
+ <section>
+ <title>Processes</title>
+ <p>One of the main reasons for using Erlang instead of other
+ functional languages is Erlang's ability to handle concurrency
+ and distributed programming. By concurrency we mean programs
+ which can handle several threads of execution at the same time.
+ For example, modern operating systems would allow you to use a
+ word processor, a spreadsheet, a mail client and a print job all
+ running at the same time. Of course each processor (CPU) in
+ the system is probably only handling one thread (or job) at a
+ time, but it swaps between the jobs a such a rate that it gives
+ the illusion of running them all at the same time. It is easy to
+ create parallel threads of execution in an Erlang program and it
+ is easy to allow these threads to communicate with each other. In
+ Erlang we call each thread of execution a <em>process</em>.</p>
+ <p>(Aside: the term "process" is usually used when the threads of
+ execution share no data with each other and the term "thread"
+ when they share data in some way. Threads of execution in Erlang
+ share no data, that's why we call them processes).</p>
+ <p>The Erlang BIF <c>spawn</c> is used to create a new process:
+ <c>spawn(Module, Exported_Function, List of Arguments)</c>.
+ Consider the following module:</p>
+ <code type="none">
+-module(tut14).
+
+-export([start/0, say_something/2]).
+
+say_something(What, 0) ->
+ done;
+say_something(What, Times) ->
+ io:format("~p~n", [What]),
+ say_something(What, Times - 1).
+
+start() ->
+ spawn(tut14, say_something, [hello, 3]),
+ spawn(tut14, say_something, [goodbye, 3]).</code>
+ <pre>
+5> <input>c(tut14).</input>
+{ok,tut14}
+6> <input>tut14:say_something(hello, 3).</input>
+hello
+hello
+hello
+done</pre>
+ <p>We can see that function <c>say_something</c> writes its first
+ argument the number of times specified by second argument. Now
+ look at the function <c>start</c>. It starts two Erlang processes,
+ one which writes "hello" three times and one which writes
+ "goodbye" three times. Both of these processes use the function
+ <c>say_something</c>. Note that a function used in this way by
+ <c>spawn</c> to start a process must be exported from the module
+ (i.e. in the <c>-export</c> at the start of the module).</p>
+ <pre>
+9> <input>tut14:start().</input>
+hello
+goodbye
+&lt;0.63.0>
+hello
+goodbye
+hello
+goodbye</pre>
+ <p>Notice that it didn't write "hello" three times and then
+ "goodbye" three times, but the first process wrote a "hello",
+ the second a "goodbye", the first another "hello" and so forth.
+ But where did the &lt;0.63.0&gt; come from? The return value of a
+ function is of course the return value of the last "thing" in
+ the function. The last thing in the function <c>start</c> is</p>
+ <code type="none">
+spawn(tut14, say_something, [goodbye, 3]).</code>
+ <p><c>spawn</c> returns a <em>process identifier</em>, or
+ <em>pid</em>, which uniquely identifies the process. So &lt;0.63.0&gt;
+ is the pid of the <c>spawn</c> function call above. We will see
+ how to use pids in the next example.</p>
+ <p>Note as well that we have used ~p instead of ~w in
+ <c>io:format</c>. To quote the manual: "~p Writes the data with
+ standard syntax in the same way as ~w, but breaks terms whose
+ printed representation is longer than one line into many lines
+ and indents each line sensibly. It also tries to detect lists of
+ printable characters and to output these as strings".</p>
+ </section>
+
+ <section>
+ <title>Message Passing</title>
+ <p>In the following example we create two processes which send
+ messages to each other a number of times.</p>
+ <code type="none">
+-module(tut15).
+
+-export([start/0, ping/2, pong/0]).
+
+ping(0, Pong_PID) ->
+ Pong_PID ! finished,
+ io:format("ping finished~n", []);
+
+ping(N, Pong_PID) ->
+ Pong_PID ! {ping, self()},
+ receive
+ pong ->
+ io:format("Ping received pong~n", [])
+ end,
+ ping(N - 1, Pong_PID).
+
+pong() ->
+ receive
+ finished ->
+ io:format("Pong finished~n", []);
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+ end.
+
+start() ->
+ Pong_PID = spawn(tut15, pong, []),
+ spawn(tut15, ping, [3, Pong_PID]).</code>
+ <pre>
+1> <input>c(tut15).</input>
+{ok,tut15}
+2> <input>tut15: start().</input>
+&lt;0.36.0>
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+ping finished
+Pong finished</pre>
+ <p>The function <c>start</c> first creates a process, let's call it
+ "pong":</p>
+ <code type="none">
+Pong_PID = spawn(tut15, pong, [])</code>
+ <p>This process executes <c>tut15:pong()</c>. <c>Pong_PID</c> is
+ the process identity of the "pong" process. The function
+ <c>start</c> now creates another process "ping".</p>
+ <code type="none">
+spawn(tut15, ping, [3, Pong_PID]),</code>
+ <p>this process executes</p>
+ <code type="none">
+tut15:ping(3, Pong_PID)</code>
+ <p>&lt;0.36.0&gt; is the return value from the <c>start</c> function.</p>
+ <p>The process "pong" now does:</p>
+ <code type="none">
+receive
+ finished ->
+ io:format("Pong finished~n", []);
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+end.</code>
+ <p>The <c>receive</c> construct is used to allow processes to wait
+ for messages from other processes. It has the format:</p>
+ <code type="none">
+receive
+ pattern1 ->
+ actions1;
+ pattern2 ->
+ actions2;
+ ....
+ patternN
+ actionsN
+end.</code>
+ <p>Note: no ";" before the <c>end</c>.</p>
+ <p>Messages between Erlang processes are simply valid Erlang terms.
+ I.e. they can be lists, tuples, integers, atoms, pids etc.</p>
+ <p>Each process has its own input queue for messages it receives.
+ New messages received are put at the end of the queue. When a
+ process executes a <c>receive</c>, the first message in the queue
+ is matched against the first pattern in the <c>receive</c>, if
+ this matches, the message is removed from the queue and
+ the actions corresponding to the the pattern are executed.</p>
+ <p>However, if the first pattern does not match, the second pattern
+ is tested, if this matches the message is removed from the queue
+ and the actions corresponding to the second pattern are executed.
+ If the second pattern does not match the third is tried and so on
+ until there are no more pattern to test. If there are no more
+ patterns to test, the first message is kept in the queue and we
+ try the second message instead. If this matches any pattern,
+ the appropriate actions are executed and the second message is
+ removed from the queue (keeping the first message and any other
+ messages in the queue). If the second message does not match we
+ try the third message and so on until we reach the end of
+ the queue. If we reach the end of the queue, the process blocks
+ (stops execution) and waits until a new message is received and
+ this procedure is repeated.</p>
+ <p>Of course the Erlang implementation is "clever" and minimizes
+ the number of times each message is tested against the patterns
+ in each <c>receive</c>.</p>
+ <p>Now back to the ping pong example.</p>
+ <p>"Pong" is waiting for messages. If the atom <c>finished</c> is
+ received, "pong" writes "Pong finished" to the output and as it
+ has nothing more to do, terminates. If it receives a message with
+ the format:</p>
+ <code type="none">
+{ping, Ping_PID}</code>
+ <p>it writes "Pong received ping" to the output and sends the atom
+ <c>pong</c> to the process "ping":</p>
+ <code type="none">
+Ping_PID ! pong</code>
+ <p>Note how the operator "!" is used to send messages. The syntax
+ of "!" is:</p>
+ <code type="none">
+Pid ! Message</code>
+ <p>I.e. <c>Message</c> (any Erlang term) is sent to the process
+ with identity <c>Pid</c>.</p>
+ <p>After sending the message <c>pong</c>, to the process "ping",
+ "pong" calls the <c>pong</c> function again, which causes it to
+ get back to the <c>receive</c> again and wait for another message.
+ Now let's look at the process "ping". Recall that it was started
+ by executing:</p>
+ <code type="none">
+tut15:ping(3, Pong_PID)</code>
+ <p>Looking at the function <c>ping/2</c> we see that the second
+ clause of <c>ping/2</c> is executed since the value of the first
+ argument is 3 (not 0) (first clause head is
+ <c>ping(0,Pong_PID)</c>, second clause head is
+ <c>ping(N,Pong_PID)</c>, so <c>N</c> becomes 3).</p>
+ <p>The second clause sends a message to "pong":</p>
+ <code type="none">
+Pong_PID ! {ping, self()},</code>
+ <p><c>self()</c> returns the pid of the process which executes
+ <c>self()</c>, in this case the pid of "ping". (Recall the code
+ for "pong", this will land up in the variable <c>Ping_PID</c> in
+ the <c>receive</c> previously explained).</p>
+ <p>"Ping" now waits for a reply from "pong":</p>
+ <code type="none">
+receive
+ pong ->
+ io:format("Ping received pong~n", [])
+end,</code>
+ <p>and writes "Ping received pong" when this reply arrives, after
+ which "ping" calls the <c>ping</c> function again.</p>
+ <code type="none">
+ping(N - 1, Pong_PID)</code>
+ <p><c>N-1</c> causes the first argument to be decremented until it
+ becomes 0. When this occurs, the first clause of <c>ping/2</c>
+ will be executed:</p>
+ <code type="none">
+ping(0, Pong_PID) ->
+ Pong_PID ! finished,
+ io:format("ping finished~n", []);</code>
+ <p>The atom <c>finished</c> is sent to "pong" (causing it to
+ terminate as described above) and "ping finished" is written to
+ the output. "Ping" then itself terminates as it has nothing left
+ to do.</p>
+ </section>
+
+ <section>
+ <title>Registered Process Names</title>
+ <p>In the above example, we first created "pong" so as to be able
+ to give the identity of "pong" when we started "ping". I.e. in
+ some way "ping" must be able to know the identity of "pong" in
+ order to be able to send a message to it. Sometimes processes
+ which need to know each others identities are started completely
+ independently of each other. Erlang thus provides a mechanism for
+ processes to be given names so that these names can be used as
+ identities instead of pids. This is done by using
+ the <c>register</c> BIF:</p>
+ <code type="none">
+register(some_atom, Pid)</code>
+ <p>We will now re-write the ping pong example using this and giving
+ the name <c>pong</c> to the "pong" process:</p>
+ <code type="none">
+-module(tut16).
+
+-export([start/0, ping/1, pong/0]).
+
+ping(0) ->
+ pong ! finished,
+ io:format("ping finished~n", []);
+
+ping(N) ->
+ pong ! {ping, self()},
+ receive
+ pong ->
+ io:format("Ping received pong~n", [])
+ end,
+ ping(N - 1).
+
+pong() ->
+ receive
+ finished ->
+ io:format("Pong finished~n", []);
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+ end.
+
+start() ->
+ register(pong, spawn(tut16, pong, [])),
+ spawn(tut16, ping, [3]).</code>
+ <pre>
+2> <input>c(tut16).</input>
+{ok, tut16}
+3> <input>tut16:start().</input>
+&lt;0.38.0>
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+ping finished
+Pong finished</pre>
+ <p>In the <c>start/0</c> function,</p>
+ <code type="none">
+register(pong, spawn(tut16, pong, [])),</code>
+ <p>both spawns the "pong" process and gives it the name <c>pong</c>.
+ In the "ping" process we can now send messages to <c>pong</c> by:</p>
+ <code type="none">
+pong ! {ping, self()},</code>
+ <p>so that <c>ping/2</c> now becomes <c>ping/1</c> as we don't have
+ to use the argument <c>Pong_PID</c>.</p>
+ </section>
+
+ <section>
+ <title>Distributed Programming</title>
+ <p>Now let's re-write the ping pong program with "ping" and "pong"
+ on different computers. Before we do this, there are a few things
+ we need to set up to get this to work. The distributed Erlang
+ implementation provides a basic security mechanism to prevent
+ unauthorized access to an Erlang system on another computer
+ (*manual*). Erlang systems which talk to each other must have
+ the same <em>magic cookie</em>. The easiest way to achieve this
+ is by having a file called <c>.erlang.cookie</c> in your home
+ directory on all machines which on which you are going to run
+ Erlang systems communicating with each other (on Windows systems
+ the home directory is the directory where pointed to by the $HOME
+ environment variable - you may need to set this. On Linux or Unix
+ you can safely ignore this and simply create a file called
+ <c>.erlang.cookie</c> in the directory you get to after executing
+ the command <c>cd</c> without any argument).
+ The <c>.erlang.cookie</c> file should contain on line with
+ the same atom. For example on Linux or Unix in the OS shell:</p>
+ <pre>
+$ <input>cd</input>
+$ <input>cat > .erlang.cookie</input>
+this_is_very_secret
+$ <input>chmod 400 .erlang.cookie</input></pre>
+ <p>The <c>chmod</c> above make the <c>.erlang.cookie</c> file
+ accessible only by the owner of the file. This is a requirement.</p>
+ <p>When you start an Erlang system which is going to talk to other
+ Erlang systems, you must give it a name, eg: </p>
+ <pre>
+$ <input>erl -sname my_name</input></pre>
+ <p>We will see more details of this later (*manual*). If you want to
+ experiment with distributed Erlang, but you only have one
+ computer to work on, you can start two separate Erlang systems on
+ the same computer but give them different names. Each Erlang
+ system running on a computer is called an Erlang node.</p>
+ <p>(Note: <c>erl -sname</c> assumes that all nodes are in the same
+ IP domain and we can use only the first component of the IP
+ address, if we want to use nodes in different domains we use
+ <c>-name</c> instead, but then all IP address must be given in
+ full (*manual*).</p>
+ <p>Here is the ping pong example modified to run on two separate
+ nodes:</p>
+ <code type="none">
+-module(tut17).
+
+-export([start_ping/1, start_pong/0, ping/2, pong/0]).
+
+ping(0, Pong_Node) ->
+ {pong, Pong_Node} ! finished,
+ io:format("ping finished~n", []);
+
+ping(N, Pong_Node) ->
+ {pong, Pong_Node} ! {ping, self()},
+ receive
+ pong ->
+ io:format("Ping received pong~n", [])
+ end,
+ ping(N - 1, Pong_Node).
+
+pong() ->
+ receive
+ finished ->
+ io:format("Pong finished~n", []);
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+ end.
+
+start_pong() ->
+ register(pong, spawn(tut17, pong, [])).
+
+start_ping(Pong_Node) ->
+ spawn(tut17, ping, [3, Pong_Node]).</code>
+ <p>Let us assume we have two computers called gollum and kosken. We
+ will start a node on kosken called ping and then a node on gollum
+ called pong.</p>
+ <p>On kosken (on a Linux/Unix system):</p>
+ <pre>
+kosken> <input>erl -sname ping</input>
+Erlang (BEAM) emulator version 5.2.3.7 [hipe] [threads:0]
+
+Eshell V5.2.3.7 (abort with ^G)
+(ping@kosken)1></pre>
+ <p>On gollum:</p>
+ <pre>
+gollum> <input>erl -sname pong</input>
+Erlang (BEAM) emulator version 5.2.3.7 [hipe] [threads:0]
+
+Eshell V5.2.3.7 (abort with ^G)
+(pong@gollum)1></pre>
+ <p>Now we start the "pong" process on gollum:</p>
+ <pre>
+(pong@gollum)1> <input>tut17:start_pong().</input>
+true</pre>
+ <p>and start the "ping" process on kosken (from the code above you
+ will see that a parameter of the <c>start_ping</c> function is
+ the node name of the Erlang system where "pong" is running):</p>
+ <pre>
+(ping@kosken)1> <input>tut17:start_ping(pong@gollum).</input>
+&lt;0.37.0>
+Ping received pong
+Ping received pong
+Ping received pong
+ping finished</pre>
+ <p>Here we see that the ping pong program has run, on the "pong"
+ side we see:</p>
+ <pre>
+(pong@gollum)2>
+Pong received ping
+Pong received ping
+Pong received ping
+Pong finished
+(pong@gollum)2></pre>
+ <p>Looking at the <c>tut17</c> code we see that the <c>pong</c>
+ function itself is unchanged, the lines:</p>
+ <code type="none">
+{ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,</code>
+ <p>work in the same way irrespective of on which node the "ping"
+ process is executing. Thus Erlang pids contain information about
+ where the process executes so if you know the pid of a process,
+ the "!" operator can be used to send it a message if the process
+ is on the same node or on a different node.</p>
+ <p>A difference is how we send messages to a registered process on
+ another node:</p>
+ <code type="none">
+{pong, Pong_Node} ! {ping, self()},</code>
+ <p>We use a tuple <c>{registered_name,node_name}</c> instead of
+ just the <c>registered_name</c>.</p>
+ <p>In the previous example, we started "ping" and "pong" from
+ the shells of two separate Erlang nodes. <c>spawn</c> can also be
+ used to start processes in other nodes. The next example is
+ the ping pong program, yet again, but this time we will start
+ "ping" in another node:</p>
+ <code type="none">
+-module(tut18).
+
+-export([start/1, ping/2, pong/0]).
+
+ping(0, Pong_Node) ->
+ {pong, Pong_Node} ! finished,
+ io:format("ping finished~n", []);
+
+ping(N, Pong_Node) ->
+ {pong, Pong_Node} ! {ping, self()},
+ receive
+ pong ->
+ io:format("Ping received pong~n", [])
+ end,
+ ping(N - 1, Pong_Node).
+
+pong() ->
+ receive
+ finished ->
+ io:format("Pong finished~n", []);
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+ end.
+
+start(Ping_Node) ->
+ register(pong, spawn(tut18, pong, [])),
+ spawn(Ping_Node, tut18, ping, [3, node()]).</code>
+ <p>Assuming an Erlang system called ping (but not the "ping"
+ process) has already been started on kosken, then on gollum we do:</p>
+ <pre>
+(pong@gollum)1> <input>tut18:start(ping@kosken).</input>
+&lt;3934.39.0>
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+Pong finished
+ping finished</pre>
+ <p>Notice we get all the output on gollum. This is because the io
+ system finds out where the process is spawned from and sends all
+ output there.</p>
+ </section>
+
+ <section>
+ <title>A Larger Example</title>
+ <p>Now for a larger example. We will make an extremely simple
+ "messenger". The messenger is a program which allows users to log
+ in on different nodes and send simple messages to each other.</p>
+ <p>Before we start, let's note the following:</p>
+ <list type="bulleted">
+ <item>
+ <p>This example will just show the message passing logic no
+ attempt at all has been made to provide a nice graphical user
+ interface - this can of course also be done in Erlang - but
+ that's another tutorial.</p>
+ </item>
+ <item>
+ <p>This sort of problem can be solved more easily if you use
+ the facilities in OTP, which will also provide methods for
+ updating code on the fly etc. But again, that's another
+ tutorial.</p>
+ </item>
+ <item>
+ <p>The first program we write will contain some inadequacies as
+ regards handling of nodes which disappear, we will correct
+ these in a later version of the program.</p>
+ </item>
+ </list>
+ <p>We will set up the messenger by allowing "clients" to connect to
+ a central server and say who and where they are. I.e. a user
+ won't need to know the name of the Erlang node where another user
+ is located to send a message.</p>
+ <p>File <c>messenger.erl</c>:</p>
+ <marker id="ex"></marker>
+ <code type="none">
+%%% Message passing utility.
+%%% User interface:
+%%% logon(Name)
+%%% One user at a time can log in from each Erlang node in the
+%%% system messenger: and choose a suitable Name. If the Name
+%%% is already logged in at another node or if someone else is
+%%% already logged in at the same node, login will be rejected
+%%% with a suitable error message.
+%%% logoff()
+%%% Logs off anybody at at node
+%%% message(ToName, Message)
+%%% sends Message to ToName. Error messages if the user of this
+%%% function is not logged on or if ToName is not logged on at
+%%% any node.
+%%%
+%%% One node in the network of Erlang nodes runs a server which maintains
+%%% data about the logged on users. The server is registered as "messenger"
+%%% Each node where there is a user logged on runs a client process registered
+%%% as "mess_client"
+%%%
+%%% Protocol between the client processes and the server
+%%% ----------------------------------------------------
+%%%
+%%% To server: {ClientPid, logon, UserName}
+%%% Reply {messenger, stop, user_exists_at_other_node} stops the client
+%%% Reply {messenger, logged_on} logon was successful
+%%%
+%%% To server: {ClientPid, logoff}
+%%% Reply: {messenger, logged_off}
+%%%
+%%% To server: {ClientPid, logoff}
+%%% Reply: no reply
+%%%
+%%% To server: {ClientPid, message_to, ToName, Message} send a message
+%%% Reply: {messenger, stop, you_are_not_logged_on} stops the client
+%%% Reply: {messenger, receiver_not_found} no user with this name logged on
+%%% Reply: {messenger, sent} Message has been sent (but no guarantee)
+%%%
+%%% To client: {message_from, Name, Message},
+%%%
+%%% Protocol between the "commands" and the client
+%%% ----------------------------------------------
+%%%
+%%% Started: messenger:client(Server_Node, Name)
+%%% To client: logoff
+%%% To client: {message_to, ToName, Message}
+%%%
+%%% Configuration: change the server_node() function to return the
+%%% name of the node where the messenger server runs
+
+-module(messenger).
+-export([start_server/0, server/1, logon/1, logoff/0, message/2, client/2]).
+
+%%% Change the function below to return the name of the node where the
+%%% messenger server runs
+server_node() ->
+ messenger@bill.
+
+%%% This is the server process for the "messenger"
+%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...]
+server(User_List) ->
+ receive
+ {From, logon, Name} ->
+ New_User_List = server_logon(From, Name, User_List),
+ server(New_User_List);
+ {From, logoff} ->
+ New_User_List = server_logoff(From, User_List),
+ server(New_User_List);
+ {From, message_to, To, Message} ->
+ server_transfer(From, To, Message, User_List),
+ io:format("list is now: ~p~n", [User_List]),
+ server(User_List)
+ end.
+
+%%% Start the server
+start_server() ->
+ register(messenger, spawn(messenger, server, [[]])).
+
+
+%%% Server adds a new user to the user list
+server_logon(From, Name, User_List) ->
+ %% check if logged on anywhere else
+ case lists:keymember(Name, 2, User_List) of
+ true ->
+ From ! {messenger, stop, user_exists_at_other_node}, %reject logon
+ User_List;
+ false ->
+ From ! {messenger, logged_on},
+ [{From, Name} | User_List] %add user to the list
+ end.
+
+%%% Server deletes a user from the user list
+server_logoff(From, User_List) ->
+ lists:keydelete(From, 1, User_List).
+
+
+%%% Server transfers a message between user
+server_transfer(From, To, Message, User_List) ->
+ %% check that the user is logged on and who he is
+ case lists:keysearch(From, 1, User_List) of
+ false ->
+ From ! {messenger, stop, you_are_not_logged_on};
+ {value, {From, Name}} ->
+ server_transfer(From, Name, To, Message, User_List)
+ end.
+%%% If the user exists, send the message
+server_transfer(From, Name, To, Message, User_List) ->
+ %% Find the receiver and send the message
+ case lists:keysearch(To, 2, User_List) of
+ false ->
+ From ! {messenger, receiver_not_found};
+ {value, {ToPid, To}} ->
+ ToPid ! {message_from, Name, Message},
+ From ! {messenger, sent}
+ end.
+
+
+%%% User Commands
+logon(Name) ->
+ case whereis(mess_client) of
+ undefined ->
+ register(mess_client,
+ spawn(messenger, client, [server_node(), Name]));
+ _ -> already_logged_on
+ end.
+
+logoff() ->
+ mess_client ! logoff.
+
+message(ToName, Message) ->
+ case whereis(mess_client) of % Test if the client is running
+ undefined ->
+ not_logged_on;
+ _ -> mess_client ! {message_to, ToName, Message},
+ ok
+end.
+
+
+%%% The client process which runs on each server node
+client(Server_Node, Name) ->
+ {messenger, Server_Node} ! {self(), logon, Name},
+ await_result(),
+ client(Server_Node).
+
+client(Server_Node) ->
+ receive
+ logoff ->
+ {messenger, Server_Node} ! {self(), logoff},
+ exit(normal);
+ {message_to, ToName, Message} ->
+ {messenger, Server_Node} ! {self(), message_to, ToName, Message},
+ await_result();
+ {message_from, FromName, Message} ->
+ io:format("Message from ~p: ~p~n", [FromName, Message])
+ end,
+ client(Server_Node).
+
+%%% wait for a response from the server
+await_result() ->
+ receive
+ {messenger, stop, Why} -> % Stop the client
+ io:format("~p~n", [Why]),
+ exit(normal);
+ {messenger, What} -> % Normal response
+ io:format("~p~n", [What])
+ end.</code>
+ <p>To use this program you need to:</p>
+ <list type="bulleted">
+ <item>configure the <c>server_node()</c> function</item>
+ <item>copy the compiled code (<c>messenger.beam</c>) to
+ the directory on each computer where you start Erlang.</item>
+ </list>
+ <p>In the following example of use of this program, I have started
+ nodes on four different computers, but if you don't have that
+ many machines available on your network, you could start up
+ several nodes on the same machine.</p>
+ <p>We start up four Erlang nodes, messenger@super, c1@bilbo,
+ c2@kosken, c3@gollum.</p>
+ <p>First we start up a the server at messenger@super:</p>
+ <pre>
+(messenger@super)1> <input>messenger:start_server().</input>
+true</pre>
+ <p>Now Peter logs on at c1@bilbo:</p>
+ <pre>
+(c1@bilbo)1> <input>messenger:logon(peter).</input>
+true
+logged_on</pre>
+ <p>James logs on at c2@kosken:</p>
+ <pre>
+(c2@kosken)1> <input>messenger:logon(james).</input>
+true
+logged_on</pre>
+ <p>and Fred logs on at c3@gollum:</p>
+ <pre>
+(c3@gollum)1> <input>messenger:logon(fred).</input>
+true
+logged_on</pre>
+ <p>Now Peter sends Fred a message:</p>
+ <pre>
+(c1@bilbo)2> <input>messenger:message(fred, "hello").</input>
+ok
+sent</pre>
+ <p>And Fred receives the message and sends a message to Peter and
+ logs off:</p>
+ <pre>
+Message from peter: "hello"
+(c3@gollum)2> <input>messenger:message(peter, "go away, I'm busy").</input>
+ok
+sent
+(c3@gollum)3> <input>messenger:logoff().</input>
+logoff</pre>
+ <p>James now tries to send a message to Fred:</p>
+ <pre>
+(c2@kosken)2> <input>messenger:message(fred, "peter doesn't like you").</input>
+ok
+receiver_not_found</pre>
+ <p>But this fails as Fred has already logged off.</p>
+ <p>First let's look at some of the new concepts we have introduced.</p>
+ <p>There are two versions of the <c>server_transfer</c> function,
+ one with four arguments (<c>server_transfer/4</c>) and one with
+ five (<c>server_transfer/5</c>). These are regarded by Erlang as
+ two separate functions.</p>
+ <p>Note how we write the <c>server</c> function so that it calls
+ itself, <c>server(User_List)</c> and thus creates a loop.
+ The Erlang compiler is "clever" and optimizes the code so that
+ this really is a sort of loop and not a proper function call. But
+ this only works if there is no code after the call, otherwise
+ the compiler will expect the call to return and make a proper
+ function call. This would result in the process getting bigger
+ and bigger for every loop.</p>
+ <p>We use functions in the <c>lists</c> module. This is a very
+ useful module and a study of the manual page is recommended
+ (<c>erl -man lists</c>).
+ <c>lists:keymember(Key,Position,Lists)</c> looks through a list
+ of tuples and looks at <c>Position</c> in each tuple to see if it
+ is the same as <c>Key</c>. The first element is position 1. If it
+ finds a tuple where the element at <c>Position</c> is the same as
+ Key, it returns <c>true</c>, otherwise <c>false</c>.</p>
+ <pre>
+3> <input>lists:keymember(a, 2, [{x,y,z},{b,b,b},{b,a,c},{q,r,s}]).</input>
+true
+4> <input>lists:keymember(p, 2, [{x,y,z},{b,b,b},{b,a,c},{q,r,s}]).</input>
+false</pre>
+ <p><c>lists:keydelete</c> works in the same way but deletes
+ the first tuple found (if any) and returns the remaining list:</p>
+ <pre>
+5> <input>lists:keydelete(a, 2, [{x,y,z},{b,b,b},{b,a,c},{q,r,s}]).</input>
+[{x,y,z},{b,b,b},{q,r,s}]</pre>
+ <p><c>lists:keysearch</c> is like <c>lists:keymember</c>, but it
+ returns <c>{value,Tuple_Found}</c> or the atom <c>false</c>.</p>
+ <p>There are a lot more very useful functions in the <c>lists</c>
+ module.</p>
+ <p>An Erlang process will (conceptually) run until it does a
+ <c>receive</c> and there is no message which it wants to receive
+ in the message queue. I say "conceptually" because the Erlang
+ system shares the CPU time between the active processes in
+ the system.</p>
+ <p>A process terminates when there is nothing more for it to do,
+ i.e. the last function it calls simply returns and doesn't call
+ another function. Another way for a process to terminate is for
+ it to call <c>exit/1</c>. The argument to <c>exit/1</c> has a
+ special meaning which we will look at later. In this example we
+ will do <c>exit(normal)</c> which has the same effect as a
+ process running out of functions to call.</p>
+ <p>The BIF <c>whereis(RegisteredName)</c> checks if a registered
+ process of name <c>RegisteredName</c> exists and return the pid
+ of the process if it does exist or the atom <c>undefined</c> if
+ it does not.</p>
+ <p>You should by now be able to understand most of the code above
+ so I'll just go through one case: a message is sent from one user
+ to another.</p>
+ <p>The first user "sends" the message in the example above by:</p>
+ <code type="none">
+messenger:message(fred, "hello")</code>
+ <p>After testing that the client process exists:</p>
+ <code type="none">
+whereis(mess_client) </code>
+ <p>and a message is sent to <c>mess_client</c>:</p>
+ <code type="none">
+mess_client ! {message_to, fred, "hello"}</code>
+ <p>The client sends the message to the server by:</p>
+ <code type="none">
+{messenger, messenger@super} ! {self(), message_to, fred, "hello"},</code>
+ <p>and waits for a reply from the server.</p>
+ <p>The server receives this message and calls:</p>
+ <code type="none">
+server_transfer(From, fred, "hello", User_List),</code>
+ <p>which checks that the pid <c>From</c> is in the <c>User_List</c>:</p>
+ <code type="none">
+lists:keysearch(From, 1, User_List) </code>
+ <p>If <c>keysearch</c> returns the atom <c>false</c>, some sort of
+ error has occurred and the server sends back the message:</p>
+ <code type="none">
+From ! {messenger, stop, you_are_not_logged_on}</code>
+ <p>which is received by the client which in turn does
+ <c>exit(normal)</c> and terminates. If <c>keysearch</c> returns
+ <c>{value,{From,Name}}</c> we know that the user is logged on and
+ is his name (peter) is in variable <c>Name</c>. We now call:</p>
+ <code type="none">
+server_transfer(From, peter, fred, "hello", User_List)</code>
+ <p>Note that as this is <c>server_transfer/5</c> it is not the same
+ as the previous function <c>server_transfer/4</c>. We do another
+ <c>keysearch</c> on <c>User_List</c> to find the pid of the client
+ corresponding to fred:</p>
+ <code type="none">
+lists:keysearch(fred, 2, User_List)</code>
+ <p>This time we use argument 2 which is the second element in
+ the tuple. If this returns the atom <c>false</c> we know that
+ fred is not logged on and we send the message:</p>
+ <code type="none">
+From ! {messenger, receiver_not_found};</code>
+ <p>which is received by the client, if <c>keysearch</c> returns:</p>
+ <code type="none">
+{value, {ToPid, fred}}</code>
+ <p>we send the message:</p>
+ <code type="none">
+ToPid ! {message_from, peter, "hello"}, </code>
+ <p>to fred's client and the message:</p>
+ <code type="none">
+From ! {messenger, sent} </code>
+ <p>to peter's client.</p>
+ <p>Fred's client receives the message and prints it:</p>
+ <code type="none">
+{message_from, peter, "hello"} ->
+ io:format("Message from ~p: ~p~n", [peter, "hello"])</code>
+ <p>and peter's client receives the message in
+ the <c>await_result</c> function.</p>
+ </section>
+</chapter>
+
diff --git a/system/doc/getting_started/intro.xml b/system/doc/getting_started/intro.xml
new file mode 100644
index 0000000000..7b42080723
--- /dev/null
+++ b/system/doc/getting_started/intro.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Introduction</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>intro.xml</file>
+ </header>
+
+ <section>
+ <title>Introduction</title>
+ <p>This is a "kick start" tutorial to get you started with Erlang.
+ Everything here is true, but only part of the truth. For example,
+ I'll only tell you the simplest form of the syntax, not all
+ esoteric forms. Where I've greatly oversimplified things I'll
+ write *manual* which means there is lots more information to be
+ found in the Erlang book or in the <em>Erlang Reference Manual</em>.</p>
+ <p>I also assume that this isn't the first time you have touched a
+ computer and you have a basic idea about how they are programmed.
+ Don't worry, I won't assume you're a wizard programmer.</p>
+ </section>
+
+ <section>
+ <title>Things Left Out</title>
+ <p>In particular the following has been omitted:</p>
+ <list type="bulleted">
+ <item>References</item>
+ <item>Local error handling (catch/throw)</item>
+ <item>Single direction links (monitor)</item>
+ <item>Handling of binary data (binaries / bit syntax)</item>
+ <item>List comprehensions</item>
+ <item>How to communicate with the outside world and/or software
+ written in other languages (ports). There is however a separate
+ tutorial for this, <em>Interoperability Tutorial</em></item>
+ <item>Very few of the Erlang libraries have been touched on (for
+ example file handling)</item>
+ <item>OTP has been totally skipped and in consequence the Mnesia
+ database has been skipped.</item>
+ <item>Hash tables for Erlang terms (ETS)</item>
+ <item>Changing code in running systems</item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/system/doc/getting_started/make.dep b/system/doc/getting_started/make.dep
new file mode 100644
index 0000000000..69b177f77c
--- /dev/null
+++ b/system/doc/getting_started/make.dep
@@ -0,0 +1,14 @@
+# ----------------------------------------------------
+# >>>> Do not edit this file <<<<
+# This file was automaticly generated by
+# /home/otp/bin/docdepend
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# TeX files that the DVI file depend on
+# ----------------------------------------------------
+
+book.dvi: book.tex conc_prog.tex intro.tex part.tex \
+ records_macros.tex robustness.tex seq_prog.tex
+
diff --git a/system/doc/getting_started/part.xml b/system/doc/getting_started/part.xml
new file mode 100644
index 0000000000..4c277419a4
--- /dev/null
+++ b/system/doc/getting_started/part.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Getting Started With Erlang</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <xi:include href="intro.xml"/>
+ <xi:include href="seq_prog.xml"/>
+ <xi:include href="conc_prog.xml"/>
+ <xi:include href="robustness.xml"/>
+ <xi:include href="records_macros.xml"/>
+</part>
+
diff --git a/system/doc/getting_started/records_macros.xml b/system/doc/getting_started/records_macros.xml
new file mode 100644
index 0000000000..45617f0183
--- /dev/null
+++ b/system/doc/getting_started/records_macros.xml
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Records and Macros</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>record_macros.xml</file>
+ </header>
+ <p>Larger programs are usually written as a collection of files with
+ a well defined interface between the various parts.</p>
+
+ <section>
+ <title>The Larger Example Divided into Several Files</title>
+ <p>To illustrate this, we will divide the messenger example from
+ the previous chapter into five files.</p>
+ <taglist>
+ <tag><c>mess_config.hrl</c></tag>
+ <item>header file for configuration data</item>
+ <tag><c>mess_interface.hrl</c></tag>
+ <item>interface definitions between the client and the messenger</item>
+ <tag><c>user_interface.erl</c></tag>
+ <item>functions for the user interface</item>
+ <tag><c>mess_client.erl</c></tag>
+ <item>functions for the client side of the messenger</item>
+ <tag><c>mess_server.erl</c></tag>
+ <item>functions for the server side of the messenger</item>
+ </taglist>
+ <p>While doing this we will also clean up the message passing
+ interface between the shell, the client and the server and define
+ it using <em>records</em>, we will also introduce <em>macros</em>.</p>
+ <code type="none">
+%%%----FILE mess_config.hrl----
+
+%%% Configure the location of the server node,
+-define(server_node, messenger@super).
+
+%%%----END FILE----</code>
+ <code type="none">
+%%%----FILE mess_interface.hrl----
+
+%%% Message interface between client and server and client shell for
+%%% messenger program
+
+%%%Messages from Client to server received in server/1 function.
+-record(logon,{client_pid, username}).
+-record(message,{client_pid, to_name, message}).
+%%% {'EXIT', ClientPid, Reason} (client terminated or unreachable.
+
+%%% Messages from Server to Client, received in await_result/0 function
+-record(abort_client,{message}).
+%%% Messages are: user_exists_at_other_node,
+%%% you_are_not_logged_on
+-record(server_reply,{message}).
+%%% Messages are: logged_on
+%%% receiver_not_found
+%%% sent (Message has been sent (no guarantee)
+%%% Messages from Server to Client received in client/1 function
+-record(message_from,{from_name, message}).
+
+%%% Messages from shell to Client received in client/1 function
+%%% spawn(mess_client, client, [server_node(), Name])
+-record(message_to,{to_name, message}).
+%%% logoff
+
+%%%----END FILE----</code>
+ <code type="none">
+%%%----FILE user_interface.erl----
+
+%%% User interface to the messenger program
+%%% login(Name)
+%%% One user at a time can log in from each Erlang node in the
+%%% system messenger: and choose a suitable Name. If the Name
+%%% is already logged in at another node or if someone else is
+%%% already logged in at the same node, login will be rejected
+%%% with a suitable error message.
+
+%%% logoff()
+%%% Logs off anybody at at node
+
+%%% message(ToName, Message)
+%%% sends Message to ToName. Error messages if the user of this
+%%% function is not logged on or if ToName is not logged on at
+%%% any node.
+
+-module(user_interface).
+-export([logon/1, logoff/0, message/2]).
+-include("mess_interface.hrl").
+-include("mess_config.hrl").
+
+logon(Name) ->
+ case whereis(mess_client) of
+ undefined ->
+ register(mess_client,
+ spawn(mess_client, client, [?server_node, Name]));
+ _ -> already_logged_on
+ end.
+
+logoff() ->
+ mess_client ! logoff.
+
+message(ToName, Message) ->
+ case whereis(mess_client) of % Test if the client is running
+ undefined ->
+ not_logged_on;
+ _ -> mess_client ! #message_to{to_name=ToName, message=Message},
+ ok
+end.
+
+%%%----END FILE----</code>
+ <code type="none">
+%%%----FILE mess_client.erl----
+
+%%% The client process which runs on each user node
+
+-module(mess_client).
+-export([client/2]).
+-include("mess_interface.hrl").
+
+client(Server_Node, Name) ->
+ {messenger, Server_Node} ! #logon{client_pid=self(), username=Name},
+ await_result(),
+ client(Server_Node).
+
+client(Server_Node) ->
+ receive
+ logoff ->
+ exit(normal);
+ #message_to{to_name=ToName, message=Message} ->
+ {messenger, Server_Node} !
+ #message{client_pid=self(), to_name=ToName, message=Message},
+ await_result();
+ {message_from, FromName, Message} ->
+ io:format("Message from ~p: ~p~n", [FromName, Message])
+ end,
+ client(Server_Node).
+
+%%% wait for a response from the server
+await_result() ->
+ receive
+ #abort_client{message=Why} ->
+ io:format("~p~n", [Why]),
+ exit(normal);
+ #server_reply{message=What} ->
+ io:format("~p~n", [What])
+ after 5000 ->
+ io:format("No response from server~n", []),
+ exit(timeout)
+ end.
+
+%%%----END FILE---</code>
+ <code type="none">
+%%%----FILE mess_server.erl----
+
+%%% This is the server process of the messenger service
+
+-module(mess_server).
+-export([start_server/0, server/0]).
+-include("mess_interface.hrl").
+
+server() ->
+ process_flag(trap_exit, true),
+ server([]).
+
+%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...]
+server(User_List) ->
+ io:format("User list = ~p~n", [User_List]),
+ receive
+ #logon{client_pid=From, username=Name} ->
+ New_User_List = server_logon(From, Name, User_List),
+ server(New_User_List);
+ {'EXIT', From, _} ->
+ New_User_List = server_logoff(From, User_List),
+ server(New_User_List);
+ #message{client_pid=From, to_name=To, message=Message} ->
+ server_transfer(From, To, Message, User_List),
+ server(User_List)
+ end.
+
+%%% Start the server
+start_server() ->
+ register(messenger, spawn(?MODULE, server, [])).
+
+%%% Server adds a new user to the user list
+server_logon(From, Name, User_List) ->
+ %% check if logged on anywhere else
+ case lists:keymember(Name, 2, User_List) of
+ true ->
+ From ! #abort_client{message=user_exists_at_other_node},
+ User_List;
+ false ->
+ From ! #server_reply{message=logged_on},
+ link(From),
+ [{From, Name} | User_List] %add user to the list
+ end.
+
+%%% Server deletes a user from the user list
+server_logoff(From, User_List) ->
+ lists:keydelete(From, 1, User_List).
+
+%%% Server transfers a message between user
+server_transfer(From, To, Message, User_List) ->
+ %% check that the user is logged on and who he is
+ case lists:keysearch(From, 1, User_List) of
+ false ->
+ From ! #abort_client{message=you_are_not_logged_on};
+ {value, {_, Name}} ->
+ server_transfer(From, Name, To, Message, User_List)
+ end.
+%%% If the user exists, send the message
+server_transfer(From, Name, To, Message, User_List) ->
+ %% Find the receiver and send the message
+ case lists:keysearch(To, 2, User_List) of
+ false ->
+ From ! #server_reply{message=receiver_not_found};
+ {value, {ToPid, To}} ->
+ ToPid ! #message_from{from_name=Name, message=Message},
+ From ! #server_reply{message=sent}
+ end.
+
+%%%----END FILE---</code>
+ </section>
+
+ <section>
+ <title>Header Files</title>
+ <p>You will see some files above with extension <c>.hrl</c>. These
+ are header files which are included in the <c>.erl</c> files by:</p>
+ <code type="none">
+-include("File_Name").</code>
+ <p>for example:</p>
+ <code type="none">
+-include("mess_interface.hrl").</code>
+ <p>In our case above the file is fetched from the same directory as
+ all the other files in the messenger example. (*manual*).</p>
+ <p>.hrl files can contain any valid Erlang code but are most often
+ used for record and macro definitions.</p>
+ </section>
+
+ <section>
+ <title>Records</title>
+ <p>A record is defined as:</p>
+ <code type="none">
+-record(name_of_record,{field_name1, field_name2, field_name3, ......}).</code>
+ <p>For example:</p>
+ <code type="none">
+-record(message_to,{to_name, message}).</code>
+ <p>This is exactly equivalent to:</p>
+ <code type="none">
+{message_to, To_Name, Message}</code>
+ <p>Creating record, is best illustrated by an example:</p>
+ <code type="none">
+#message_to{message="hello", to_name=fred)</code>
+ <p>This will create:</p>
+ <code type="none">
+{message_to, fred, "hello"}</code>
+ <p>Note that you don't have to worry about the order you assign
+ values to the various parts of the records when you create it.
+ The advantage of using records is that by placing their
+ definitions in header files you can conveniently define
+ interfaces which are easy to change. For example, if you want to
+ add a new field to the record, you will only have to change
+ the code where the new field is used and not at every place
+ the record is referred to. If you leave out a field when creating
+ a record, it will get the value of the atom undefined. (*manual*)</p>
+ <p>Pattern matching with records is very similar to creating
+ records. For example inside a <c>case</c> or <c>receive</c>:</p>
+ <code type="none">
+#message_to{to_name=ToName, message=Message} -></code>
+ <p>is the same as:</p>
+ <code type="none">
+{message_to, ToName, Message}</code>
+ </section>
+
+ <section>
+ <title>Macros</title>
+ <p>The other thing we have added to the messenger is a macro.
+ The file <c>mess_config.hrl</c> contains the definition:</p>
+ <code type="none">
+%%% Configure the location of the server node,
+-define(server_node, messenger@super).</code>
+ <p>We include this file in mess_server.erl:</p>
+ <code type="none">
+-include("mess_config.hrl").</code>
+ <p>Every occurrence of <c>?server_node</c> in <c>mess_server.erl</c>
+ will now be replaced by <c>messenger@super</c>.</p>
+ <p>The other place a macro is used is when we spawn the server
+ process:</p>
+ <code type="none">
+spawn(?MODULE, server, [])</code>
+ <p>This is a standard macro (i.e. defined by the system, not
+ the user). <c>?MODULE</c> is always replaced by the name of
+ current module (i.e. the <c>-module</c> definition near the start
+ of the file). There are more advanced ways of using macros with,
+ for example parameters (*manual*).</p>
+ <p>The three Erlang (<c>.erl</c>) files in the messenger example are
+ individually compiled into object code file (<c>.beam</c>).
+ The Erlang system loads and links these files into the system
+ when they are referred to during execution of the code. In our
+ case we simply have put them in the same directory which is our
+ current working directory (i.e. the place we have done "cd" to).
+ There are ways of putting the <c>.beam</c> files in other
+ directories.</p>
+ <p>In the messenger example, no assumptions have been made about
+ what the message being sent is. It could be any valid Erlang term.</p>
+ </section>
+</chapter>
+
diff --git a/system/doc/getting_started/robustness.xml b/system/doc/getting_started/robustness.xml
new file mode 100644
index 0000000000..227da4c027
--- /dev/null
+++ b/system/doc/getting_started/robustness.xml
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Robustness</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>robustness.xml</file>
+ </header>
+ <p>There are several things which are wrong with
+ the <seealso marker="conc_prog#ex">messenger example</seealso> from
+ the previous chapter. For example if a node where a user is logged
+ on goes down without doing a log off, the user will remain in
+ the server's <c>User_List</c> but the client will disappear thus
+ making it impossible for the user to log on again as the server
+ thinks the user already logged on.</p>
+ <p>Or what happens if the server goes down in the middle of sending a
+ message leaving the sending client hanging for ever in
+ the <c>await_result</c> function?</p>
+
+ <section>
+ <title>Timeouts</title>
+ <p>Before improving the messenger program we will look into some
+ general principles, using the ping pong program as an example.
+ Recall that when "ping" finishes, it tells "pong" that it has
+ done so by sending the atom <c>finished</c> as a message to "pong"
+ so that "pong" could also finish. Another way to let "pong"
+ finish, is to make "pong" exit if it does not receive a message
+ from ping within a certain time, this can be done by adding a
+ <em>timeout</em> to <c>pong</c> as shown in the following example:</p>
+ <code type="none">
+-module(tut19).
+
+-export([start_ping/1, start_pong/0, ping/2, pong/0]).
+
+ping(0, Pong_Node) ->
+ io:format("ping finished~n", []);
+
+ping(N, Pong_Node) ->
+ {pong, Pong_Node} ! {ping, self()},
+ receive
+ pong ->
+ io:format("Ping received pong~n", [])
+ end,
+ ping(N - 1, Pong_Node).
+
+pong() ->
+ receive
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+ after 5000 ->
+ io:format("Pong timed out~n", [])
+ end.
+
+start_pong() ->
+ register(pong, spawn(tut19, pong, [])).
+
+start_ping(Pong_Node) ->
+ spawn(tut19, ping, [3, Pong_Node]).</code>
+ <p>After we have compiled this and copied the <c>tut19.beam</c>
+ file to the necessary directories:</p>
+ <p>On (pong@kosken):</p>
+ <pre>
+(pong@kosken)1> <input>tut19:start_pong().</input>
+true
+Pong received ping
+Pong received ping
+Pong received ping
+Pong timed out</pre>
+ <p>On (ping@gollum):</p>
+ <pre>
+(ping@gollum)1> <input>tut19:start_ping(pong@kosken).</input>
+&lt;0.36.0>
+Ping received pong
+Ping received pong
+Ping received pong
+ping finished </pre>
+ <p>(The timeout is set in:</p>
+ <code type="none">
+pong() ->
+ receive
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+ after 5000 ->
+ io:format("Pong timed out~n", [])
+ end.</code>
+ <p>We start the timeout (<c>after 5000</c>) when we enter
+ <c>receive</c>. The timeout is canceled if <c>{ping,Ping_PID}</c>
+ is received. If <c>{ping,Ping_PID}</c> is not received,
+ the actions following the timeout will be done after 5000
+ milliseconds. <c>after</c> must be last in the <c>receive</c>,
+ i.e. preceded by all other message reception specifications in
+ the <c>receive</c>. Of course we could also call a function which
+ returned an integer for the timeout:</p>
+ <code type="none">
+after pong_timeout() -></code>
+ <p>In general, there are better ways than using timeouts to
+ supervise parts of a distributed Erlang system. Timeouts are
+ usually appropriate to supervise external events, for example if
+ you have expected a message from some external system within a
+ specified time. For example, we could use a timeout to log a user
+ out of the messenger system if they have not accessed it, for
+ example, in ten minutes.</p>
+ </section>
+
+ <section>
+ <title>Error Handling</title>
+ <p>Before we go into details of the supervision and error handling
+ in an Erlang system, we need see how Erlang processes terminate,
+ or in Erlang terminology, <em>exit</em>.</p>
+ <p>A process which executes <c>exit(normal)</c> or simply runs out
+ of things to do has a <em>normal</em> exit.</p>
+ <p>A process which encounters a runtime error (e.g. divide by zero,
+ bad match, trying to call a function which doesn't exist etc)
+ exits with an error, i.e. has an <em>abnormal</em> exit. A
+ process which executes
+ <seealso marker="erts:erlang#exit/1">exit(Reason)</seealso>
+ where <c>Reason</c> is any Erlang term except the atom
+ <c>normal</c>, also has an abnormal exit.</p>
+ <p>An Erlang process can set up links to other Erlang processes. If
+ a process calls
+ <seealso marker="erts:erlang#link/1">link(Other_Pid)</seealso>
+ it sets up a bidirectional link between itself and the process
+ called <c>Other_Pid</c>. When a process terminates its sends
+ something called a <em>signal</em> to all the processes it has
+ links to.</p>
+ <p>The signal carries information about the pid it was sent from and
+ the exit reason.</p>
+ <p>The default behaviour of a process which receives a normal exit
+ is to ignore the signal.</p>
+ <p>The default behaviour in the two other cases (i.e. abnormal exit)
+ above is to bypass all messages to the receiving process and to
+ kill it and to propagate the same error signal to the killed
+ process' links. In this way you can connect all processes in a
+ transaction together using links and if one of the processes
+ exits abnormally, all the processes in the transaction will be
+ killed. As we often want to create a process and link to it at
+ the same time, there is a special BIF,
+ <seealso marker="erts:erlang#spawn_link/1">spawn_link</seealso>
+ which does the same as <c>spawn</c>, but also creates a link to
+ the spawned process.</p>
+ <p>Now an example of the ping pong example using links to terminate
+ "pong":</p>
+ <code type="none">
+-module(tut20).
+
+-export([start/1, ping/2, pong/0]).
+
+ping(N, Pong_Pid) ->
+ link(Pong_Pid),
+ ping1(N, Pong_Pid).
+
+ping1(0, _) ->
+ exit(ping);
+
+ping1(N, Pong_Pid) ->
+ Pong_Pid ! {ping, self()},
+ receive
+ pong ->
+ io:format("Ping received pong~n", [])
+ end,
+ ping1(N - 1, Pong_Pid).
+
+pong() ->
+ receive
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong()
+ end.
+
+start(Ping_Node) ->
+ PongPID = spawn(tut20, pong, []),
+ spawn(Ping_Node, tut20, ping, [3, PongPID]).</code>
+ <pre>
+(s1@bill)3> <input>tut20:start(s2@kosken).</input>
+Pong received ping
+&lt;3820.41.0>
+Ping received pong
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong</pre>
+ <p>This is a slight modification of the ping pong program where both
+ processes are spawned from the same <c>start/1</c> function,
+ where the "ping" process can be spawned on a separate node. Note
+ the use of the <c>link</c> BIF. "Ping" calls
+ <c>exit(ping)</c> when it finishes and this will cause an exit
+ signal to be sent to "pong" which will also terminate.</p>
+ <p>It is possible to modify the default behaviour of a process so
+ that it does not get killed when it receives abnormal exit
+ signals, but all signals will be turned into normal messages on
+ the format <c>{'EXIT',FromPID,Reason}</c> and added to the end of
+ the receiving processes message queue. This behaviour is set by:</p>
+ <code type="none">
+process_flag(trap_exit, true)</code>
+ <p>There are several other process flags, see
+ <seealso marker="erts:erlang#process_flag/2">erlang(3)</seealso>.
+ Changing the default behaviour of a process in this way is
+ usually not done in standard user programs, but is left to
+ the supervisory programs in OTP (but that's another tutorial).
+ However we will modify the ping pong program to illustrate exit
+ trapping.</p>
+ <code type="none">
+-module(tut21).
+
+-export([start/1, ping/2, pong/0]).
+
+ping(N, Pong_Pid) ->
+ link(Pong_Pid),
+ ping1(N, Pong_Pid).
+
+ping1(0, _) ->
+ exit(ping);
+
+ping1(N, Pong_Pid) ->
+ Pong_Pid ! {ping, self()},
+ receive
+ pong ->
+ io:format("Ping received pong~n", [])
+ end,
+ ping1(N - 1, Pong_Pid).
+
+pong() ->
+ process_flag(trap_exit, true),
+ pong1().
+
+pong1() ->
+ receive
+ {ping, Ping_PID} ->
+ io:format("Pong received ping~n", []),
+ Ping_PID ! pong,
+ pong1();
+ {'EXIT', From, Reason} ->
+ io:format("pong exiting, got ~p~n", [{'EXIT', From, Reason}])
+ end.
+
+start(Ping_Node) ->
+ PongPID = spawn(tut21, pong, []),
+ spawn(Ping_Node, tut21, ping, [3, PongPID]).</code>
+ <pre>
+(s1@bill)1> <input>tut21:start(s2@gollum).</input>
+&lt;3820.39.0>
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+Pong received ping
+Ping received pong
+pong exiting, got {'EXIT',&lt;3820.39.0>,ping}</pre>
+ </section>
+
+ <section>
+ <title>The Larger Example with Robustness Added</title>
+ <p>Now we return to the messenger program and add changes which
+ make it more robust:</p>
+ <code type="none">
+%%% Message passing utility.
+%%% User interface:
+%%% login(Name)
+%%% One user at a time can log in from each Erlang node in the
+%%% system messenger: and choose a suitable Name. If the Name
+%%% is already logged in at another node or if someone else is
+%%% already logged in at the same node, login will be rejected
+%%% with a suitable error message.
+%%% logoff()
+%%% Logs off anybody at at node
+%%% message(ToName, Message)
+%%% sends Message to ToName. Error messages if the user of this
+%%% function is not logged on or if ToName is not logged on at
+%%% any node.
+%%%
+%%% One node in the network of Erlang nodes runs a server which maintains
+%%% data about the logged on users. The server is registered as "messenger"
+%%% Each node where there is a user logged on runs a client process registered
+%%% as "mess_client"
+%%%
+%%% Protocol between the client processes and the server
+%%% ----------------------------------------------------
+%%%
+%%% To server: {ClientPid, logon, UserName}
+%%% Reply {messenger, stop, user_exists_at_other_node} stops the client
+%%% Reply {messenger, logged_on} logon was successful
+%%%
+%%% When the client terminates for some reason
+%%% To server: {'EXIT', ClientPid, Reason}
+%%%
+%%% To server: {ClientPid, message_to, ToName, Message} send a message
+%%% Reply: {messenger, stop, you_are_not_logged_on} stops the client
+%%% Reply: {messenger, receiver_not_found} no user with this name logged on
+%%% Reply: {messenger, sent} Message has been sent (but no guarantee)
+%%%
+%%% To client: {message_from, Name, Message},
+%%%
+%%% Protocol between the "commands" and the client
+%%% ----------------------------------------------
+%%%
+%%% Started: messenger:client(Server_Node, Name)
+%%% To client: logoff
+%%% To client: {message_to, ToName, Message}
+%%%
+%%% Configuration: change the server_node() function to return the
+%%% name of the node where the messenger server runs
+
+-module(messenger).
+-export([start_server/0, server/0,
+ logon/1, logoff/0, message/2, client/2]).
+
+%%% Change the function below to return the name of the node where the
+%%% messenger server runs
+server_node() ->
+ messenger@super.
+
+%%% This is the server process for the "messenger"
+%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...]
+server() ->
+ process_flag(trap_exit, true),
+ server([]).
+
+server(User_List) ->
+ receive
+ {From, logon, Name} ->
+ New_User_List = server_logon(From, Name, User_List),
+ server(New_User_List);
+ {'EXIT', From, _} ->
+ New_User_List = server_logoff(From, User_List),
+ server(New_User_List);
+ {From, message_to, To, Message} ->
+ server_transfer(From, To, Message, User_List),
+ io:format("list is now: ~p~n", [User_List]),
+ server(User_List)
+ end.
+
+%%% Start the server
+start_server() ->
+ register(messenger, spawn(messenger, server, [])).
+
+%%% Server adds a new user to the user list
+server_logon(From, Name, User_List) ->
+ %% check if logged on anywhere else
+ case lists:keymember(Name, 2, User_List) of
+ true ->
+ From ! {messenger, stop, user_exists_at_other_node}, %reject logon
+ User_List;
+ false ->
+ From ! {messenger, logged_on},
+ link(From),
+ [{From, Name} | User_List] %add user to the list
+ end.
+
+%%% Server deletes a user from the user list
+server_logoff(From, User_List) ->
+ lists:keydelete(From, 1, User_List).
+
+
+%%% Server transfers a message between user
+server_transfer(From, To, Message, User_List) ->
+ %% check that the user is logged on and who he is
+ case lists:keysearch(From, 1, User_List) of
+ false ->
+ From ! {messenger, stop, you_are_not_logged_on};
+ {value, {_, Name}} ->
+ server_transfer(From, Name, To, Message, User_List)
+ end.
+
+%%% If the user exists, send the message
+server_transfer(From, Name, To, Message, User_List) ->
+ %% Find the receiver and send the message
+ case lists:keysearch(To, 2, User_List) of
+ false ->
+ From ! {messenger, receiver_not_found};
+ {value, {ToPid, To}} ->
+ ToPid ! {message_from, Name, Message},
+ From ! {messenger, sent}
+ end.
+
+%%% User Commands
+logon(Name) ->
+ case whereis(mess_client) of
+ undefined ->
+ register(mess_client,
+ spawn(messenger, client, [server_node(), Name]));
+ _ -> already_logged_on
+ end.
+
+logoff() ->
+ mess_client ! logoff.
+
+message(ToName, Message) ->
+ case whereis(mess_client) of % Test if the client is running
+ undefined ->
+ not_logged_on;
+ _ -> mess_client ! {message_to, ToName, Message},
+ ok
+end.
+
+%%% The client process which runs on each user node
+client(Server_Node, Name) ->
+ {messenger, Server_Node} ! {self(), logon, Name},
+ await_result(),
+ client(Server_Node).
+
+client(Server_Node) ->
+ receive
+ logoff ->
+ exit(normal);
+ {message_to, ToName, Message} ->
+ {messenger, Server_Node} ! {self(), message_to, ToName, Message},
+ await_result();
+ {message_from, FromName, Message} ->
+ io:format("Message from ~p: ~p~n", [FromName, Message])
+ end,
+ client(Server_Node).
+
+%%% wait for a response from the server
+await_result() ->
+ receive
+ {messenger, stop, Why} -> % Stop the client
+ io:format("~p~n", [Why]),
+ exit(normal);
+ {messenger, What} -> % Normal response
+ io:format("~p~n", [What])
+ after 5000 ->
+ io:format("No response from server~n", []),
+ exit(timeout)
+ end.</code>
+ <p>We have added the following changes:</p>
+ <p>The messenger server traps exits. If it receives an exit signal,
+ <c>{'EXIT',From,Reason}</c> this means that a client process has
+ terminated or is unreachable because:</p>
+ <list type="bulleted">
+ <item>the user has logged off (we have removed the "logoff"
+ message),</item>
+ <item>the network connection to the client is broken,</item>
+ <item>the node on which the client process resides has gone down,
+ or</item>
+ <item>the client processes has done some illegal operation.</item>
+ </list>
+ <p>If we receive an exit signal as above, we delete the tuple,
+ <c>{From,Name}</c> from the servers <c>User_List</c> using
+ the <c>server_logoff</c> function. If the node on which the server
+ runs goes down, an exit signal (automatically generated by
+ the system), will be sent to all of the client processes:
+ <c>{'EXIT',MessengerPID,noconnection}</c> causing all the client
+ processes to terminate.</p>
+ <p>We have also introduced a timeout of five seconds in
+ the <c>await_result</c> function. I.e. if the server does not
+ reply within five seconds (5000 ms), the client terminates. This
+ is really only needed in the logon sequence before the client and
+ server are linked.</p>
+ <p>An interesting case is if the client was to terminate before
+ the server links to it. This is taken care of because linking to a
+ non-existent process causes an exit signal,
+ <c>{'EXIT',From,noproc}</c>, to be automatically generated as if
+ the process terminated immediately after the link operation.</p>
+ </section>
+</chapter>
+
diff --git a/system/doc/getting_started/seq_prog.xml b/system/doc/getting_started/seq_prog.xml
new file mode 100644
index 0000000000..bc1758d855
--- /dev/null
+++ b/system/doc/getting_started/seq_prog.xml
@@ -0,0 +1,1231 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Sequential Programming</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>seq_prog.xml</file>
+ </header>
+
+ <section>
+ <title>The Erlang Shell</title>
+ <p>Most operating systems have a command interpreter or shell, Unix
+ and Linux have many, Windows has the Command Prompt. Erlang has
+ its own shell where you can directly write bits of Erlang code
+ and evaluate (run) them to see what happens (see
+ <seealso marker="stdlib:shell">shell(3)</seealso>). Start
+ the Erlang shell (in Linux or UNIX) by starting a shell or
+ command interpreter in your operating system and typing
+ <c>erl</c>, you will see something like this.</p>
+ <pre>
+% <input>erl</input>
+Erlang (BEAM) emulator version 5.2 [source] [hipe]
+
+Eshell V5.2 (abort with ^G)
+1></pre>
+ <p>Now type in "2 + 5." as shown below.</p>
+ <pre>
+1> <input>2 + 5.</input>
+7
+2></pre>
+ <p>In Windows, the shell is started by double-clicking on the Erlang
+ shell icon.</p>
+ <p>You'll notice that the Erlang shell has numbered the lines that
+ can be entered, (as 1&gt; 2&gt;) and that it has correctly told you
+ that 2 + 5 is 7! Also notice that you have to tell it you are
+ done entering code by finishing with a full stop "." and a
+ carriage return. If you make mistakes writing things in the shell,
+ you can delete things by using the backspace key as in most
+ shells. There are many more editing commands in the shell
+ (See the chapter <seealso marker="erts:tty">"tty - A command line interface"</seealso> in ERTS User's Guide).</p>
+ <p>(Note: you will find a lot of line numbers given by the shell
+ out of sequence in this tutorial as it was written and the code
+ tested in several sessions).</p>
+ <p>Now let's try a more complex calculation.</p>
+ <pre>
+2> <input>(42 + 77) * 66 / 3.</input>
+2618.0</pre>
+ <p>Here you can see the use of brackets and the multiplication
+ operator "*" and division operator "/", just as in normal
+ arithmetic (see the chapter
+ <seealso marker="doc/reference_manual:expressions">"Arithmetic Expressions"</seealso> in the Erlang Reference Manual).</p>
+ <p>To shutdown the Erlang system and the Erlang shell type
+ Control-C. You will see the following output:</p>
+ <pre>
+BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
+ (v)ersion (k)ill (D)b-tables (d)istribution
+<input>a</input>
+%</pre>
+ <p>Type "a" to leave the Erlang system.</p>
+ <p>Another way to shutdown the Erlang system is by entering
+ <c>halt()</c>:</p>
+ <pre>
+3> <input>halt().</input>
+% </pre>
+ </section>
+
+ <section>
+ <title>Modules and Functions</title>
+ <p>A programming language isn't much use if you can just run code
+ from the shell. So here is a small Erlang program. Enter it into
+ a file called <c>tut.erl</c> (the file name <c>tut.erl</c> is
+ important, also make sure that it is in the same directory as
+ the one where you started <c>erl</c>) using a suitable
+ text editor. If you are lucky your editor will have an Erlang
+ mode which will make it easier for you to enter and format your
+ code nicely (see the chapter
+ <seealso marker="tools:erlang_mode_chapter">"The Erlang mode for Emacs"</seealso> in Tools User's Guide), but you can manage
+ perfectly well without. Here's the code to enter:</p>
+ <code type="none">
+-module(tut).
+-export([double/1]).
+
+double(X) ->
+ 2 * X.</code>
+ <p>It's not hard to guess that this "program" doubles the value of
+ numbers. I'll get back to the first two lines later. Let's compile
+ the program. This can be done in your Erlang shell as shown below:</p>
+ <pre>
+3> <input>c(tut).</input>
+{ok,tut}</pre>
+ <p>The <c>{ok,tut}</c> tells you that the compilation was OK. If it
+ said "error" instead, you have made some mistake in the text you
+ entered and there will also be error messages to give you some
+ idea as to what has gone wrong so you can change what you have
+ written and try again.</p>
+ <p>Now lets run the program.</p>
+ <pre>
+4> <input>tut:double(10).</input>
+20</pre>
+ <p>As expected double of 10 is 20.</p>
+ <p>Now let's get back to the first two lines. Erlang programs are
+ written in files. Each file contains what we call an Erlang
+ <em>module</em>. The first line of code in the module tells us
+ the name of the module (see the chapter
+ <seealso marker="doc/reference_manual:modules">"Modules"</seealso>
+ in the Erlang Reference Manual).</p>
+ <code type="none">
+-module(tut).</code>
+ <p>This tells us that the module is called <em>tut</em>. Note
+ the "." at the end of the line. The files which are used to store
+ the module must have the same name as the module but with
+ the extension ".erl". In our case the file name is <c>tut.erl</c>.
+ When we use a function in another module, we use the syntax,
+ <c>module_name:function_name(arguments)</c>. So</p>
+ <pre>
+4> <input>tut:double(10).</input></pre>
+ <p>means call function <c>double</c> in module <c>tut</c> with
+ argument "10".</p>
+ <p>The second line:</p>
+ <code type="none">
+-export([double/1]).</code>
+ <p>says that the module <c>tut</c> contains a function called
+ <c>double</c> which takes one argument (<c>X</c> in our example)
+ and that this function can be called from outside the module
+ <c>tut</c>. More about this later. Again note the "." at the end
+ of the line.</p>
+ <p>Now for a more complicated example, the factorial of a number
+ (e.g. factorial of 4 is 4 * 3 * 2 * 1). Enter the following code
+ in a file called <c>tut1.erl</c>.</p>
+ <code type="none">
+-module(tut1).
+-export([fac/1]).
+
+fac(1) ->
+ 1;
+fac(N) ->
+ N * fac(N - 1).</code>
+ <p>Compile the file</p>
+ <pre>
+5> <input>c(tut1).</input>
+{ok,tut1}</pre>
+ <p>And now calculate the factorial of 4.</p>
+ <pre>
+6> <input>tut1:fac(4).</input>
+24</pre>
+ <p>The first part:</p>
+ <code type="none">
+fac(1) ->
+ 1;</code>
+ <p>says that the factorial of 1 is 1. Note that we end this part
+ with a ";" which indicates that there is more of this function to
+ come. The second part:</p>
+ <code type="none">
+fac(N) ->
+ N * fac(N - 1).</code>
+ <p>says that the factorial of N is N multiplied by the factorial of
+ N - 1. Note that this part ends with a "." saying that there are
+ no more parts of this function.</p>
+ <p>A function can have many arguments. Let's expand the module
+ <c>tut1</c> with the rather stupid function to multiply two
+ numbers:</p>
+ <code type="none">
+-module(tut1).
+-export([fac/1, mult/2]).
+
+fac(1) ->
+ 1;
+fac(N) ->
+ N * fac(N - 1).
+
+mult(X, Y) ->
+ X * Y.</code>
+ <p>Note that we have also had to expand the <c>-export</c> line
+ with the information that there is another function <c>mult</c>
+ with two arguments.</p>
+ <p>Compile:</p>
+ <pre>
+7> <input>c(tut1).</input>
+{ok,tut1}</pre>
+ <p>and try it out:</p>
+ <pre>
+8> <input>tut1:mult(3,4).</input>
+12</pre>
+ <p>In the example above the numbers are integers and the arguments
+ in the functions in the code, <c>N</c>, <c>X</c>, <c>Y</c> are
+ called variables. Variables must start with a capital letter
+ (see the chapter
+ <seealso marker="doc/reference_manual:expressions">"Variables"</seealso>
+ in the Erlang Reference Manual). Examples of variable could be
+ <c>Number</c>, <c>ShoeSize</c>, <c>Age</c> etc.</p>
+ </section>
+
+ <section>
+ <title>Atoms</title>
+ <p>Atoms are another data type in Erlang. Atoms start with a small
+ letter ((see the chapter
+ <seealso marker="doc/reference_manual:data_types">"Atom"</seealso>
+ in the Erlang Reference Manual)), for example: <c>charles</c>,
+ <c>centimeter</c>, <c>inch</c>. Atoms are simply names, nothing
+ else. They are not like variables which can have a value.</p>
+ <p>Enter the next program (file: <c>tut2.erl</c>) which could be
+ useful for converting from inches to centimeters and vice versa:</p>
+ <code type="none">
+-module(tut2).
+-export([convert/2]).
+
+convert(M, inch) ->
+ M / 2.54;
+
+convert(N, centimeter) ->
+ N * 2.54.</code>
+ <p>Compile and test:</p>
+ <pre>
+9> <input>c(tut2).</input>
+{ok,tut2}
+10> <input>tut2:convert(3, inch).</input>
+1.1811023622047243
+11> <input>tut2:convert(7, centimeter).</input>
+17.78</pre>
+ <p>Notice that I have introduced decimals (floating point numbers)
+ without any explanation, but I guess you can cope with that.</p>
+ <p>See what happens if I enter something other than centimeter or
+ inch in the convert function:</p>
+ <pre>
+12> <input>tut2:convert(3, miles).</input>
+** exception error: no function clause matching tut2:convert(3,miles)</pre>
+ <p>The two parts of the <c>convert</c> function are called its
+ clauses. Here we see that "miles" is not part of either of
+ the clauses. The Erlang system can't <em>match</em> either of
+ the clauses so we get an error message <c>function_clause</c>.
+ The shell formats the error message nicely, but the error tuple
+ is saved in the shell's history list and can be output by the shell
+ command <c>v/1</c>:</p>
+ <pre>
+13> <input>v(12).</input>
+{'EXIT',{function_clause,[{tut2,convert,[3,miles]},
+ {erl_eval,do_apply,5},
+ {shell,exprs,6},
+ {shell,eval_exprs,6},
+ {shell,eval_loop,3}]}}</pre>
+
+ </section>
+
+ <section>
+ <title>Tuples</title>
+ <p>Now the <c>tut2</c> program is hardly good programming style.
+ Consider:</p>
+ <code type="none">
+tut2:convert(3, inch).</code>
+ <p>Does this mean that 3 is in inches? or that 3 is in centimeters
+ and we want to convert it to inches? So Erlang has a way to group
+ things together to make things more understandable. We call these
+ <em>tuples</em>. Tuples are surrounded by "{" and "}".</p>
+ <p>So we can write <c>{inch,3}</c> to denote 3 inches and
+ <c>{centimeter,5}</c> to denote 5 centimeters. Now let's write a
+ new program which converts centimeters to inches and vice versa.
+ (file <c>tut3.erl</c>).</p>
+ <code type="none">
+-module(tut3).
+-export([convert_length/1]).
+
+convert_length({centimeter, X}) ->
+ {inch, X / 2.54};
+convert_length({inch, Y}) ->
+ {centimeter, Y * 2.54}.</code>
+ <p>Compile and test:</p>
+ <pre>
+14> <input>c(tut3).</input>
+{ok,tut3}
+15> <input>tut3:convert_length({inch, 5}).</input>
+{centimeter,12.7}
+16> <input>tut3:convert_length(tut3:convert_length({inch, 5})).</input>
+{inch,5.0}</pre>
+ <p>Note on line 16 we convert 5 inches to centimeters and back
+ again and reassuringly get back to the original value. I.e
+ the argument to a function can be the result of another function.
+ Pause for a moment and consider how line 16 (above) works.
+ The argument we have given the function <c>{inch,5}</c> is first
+ matched against the first head clause of <c>convert_length</c>
+ i.e. <c>convert_length({centimeter,X})</c> where it can be seen
+ that <c>{centimeter,X}</c> does not match <c>{inch,5}</c>
+ (the head is the bit before the "-&gt;"). This having failed, we try
+ the head of the next clause i.e. <c>convert_length({inch,Y})</c>,
+ this matches and <c>Y</c> get the value 5.</p>
+ <p>We have shown tuples with two parts above, but tuples can have
+ as many parts as we want and contain any valid Erlang
+ <em>term</em>. For example, to represent the temperature of
+ various cities of the world we could write</p>
+ <code type="none">
+{moscow, {c, -10}}
+{cape_town, {f, 70}}
+{paris, {f, 28}}</code>
+ <p>Tuples have a fixed number of things in them. We call each thing
+ in a tuple an element. So in the tuple <c>{moscow,{c,-10}}</c>,
+ element 1 is <c>moscow</c> and element 2 is <c>{c,-10}</c>. I
+ have chosen <c>c</c> meaning Centigrade (or Celsius) and <c>f</c>
+ meaning Fahrenheit.</p>
+ </section>
+
+ <section>
+ <title>Lists</title>
+ <p>Whereas tuples group things together, we also want to be able to
+ represent lists of things. Lists in Erlang are surrounded by "["
+ and "]". For example a list of the temperatures of various cities
+ in the world could be:</p>
+ <code type="none">
+[{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}},
+ {paris, {f, 28}}, {london, {f, 36}}]</code>
+ <p>Note that this list was so long that it didn't fit on one line.
+ This doesn't matter, Erlang allows line breaks at all "sensible
+ places" but not, for example, in the middle of atoms, integers
+ etc.</p>
+ <p>A very useful way of looking at parts of lists, is by using "|".
+ This is best explained by an example using the shell.</p>
+ <pre>
+17> <input>[First |TheRest] = [1,2,3,4,5].</input>
+[1,2,3,4,5]
+18> <input>First.</input>
+1
+19> <input>TheRest.</input>
+[2,3,4,5]</pre>
+ <p>We use | to separate the first elements of the list from
+ the rest of the list. (<c>First</c> has got value 1 and
+ <c>TheRest</c> value [2,3,4,5]).</p>
+ <p>Another example:</p>
+ <pre>
+20> <input>[E1, E2 | R] = [1,2,3,4,5,6,7].</input>
+[1,2,3,4,5,6,7]
+21> <input>E1.</input>
+1
+22> <input>E2.</input>
+2
+23> <input>R.</input>
+[3,4,5,6,7]</pre>
+ <p>Here we see the use of | to get the first two elements from
+ the list. Of course if we try to get more elements from the list
+ than there are elements in the list we will get an error. Note
+ also the special case of the list with no elements [].</p>
+ <pre>
+24> <input>[A, B | C] = [1, 2].</input>
+[1,2]
+25> <input>A.</input>
+1
+26> <input>B.</input>
+2
+27> <input>C.</input>
+[]</pre>
+ <p>In all the examples above, I have been using new variable names,
+ not reusing the old ones: <c>First</c>, <c>TheRest</c>, <c>E1</c>,
+ <c>E2</c>, <c>R</c>, <c>A</c>, <c>B</c>, <c>C</c>. The reason
+ for this is that a variable can only be given a value once in its
+ context (scope). I'll get back to this later, it isn't so
+ peculiar as it sounds!</p>
+ <p>The following example shows how we find the length of a list:</p>
+ <code type="none">
+-module(tut4).
+
+-export([list_length/1]).
+
+list_length([]) ->
+ 0;
+list_length([First | Rest]) ->
+ 1 + list_length(Rest).</code>
+ <p>Compile (file <c>tut4.erl</c>) and test:</p>
+ <pre>
+28> <input>c(tut4).</input>
+{ok,tut4}
+29> <input>tut4:list_length([1,2,3,4,5,6,7]).</input>
+7</pre>
+ <p>Explanation:</p>
+ <code type="none">
+list_length([]) ->
+ 0;</code>
+ <p>The length of an empty list is obviously 0.</p>
+ <code type="none">
+list_length([First | Rest]) ->
+ 1 + list_length(Rest).</code>
+ <p>The length of a list with the first element <c>First</c> and
+ the remaining elements <c>Rest</c> is 1 + the length of
+ <c>Rest</c>.</p>
+ <p>(Advanced readers only: This is not tail recursive, there is a
+ better way to write this function).</p>
+ <p>In general we can say we use tuples where we would use "records"
+ or "structs" in other languages and we use lists when we want to
+ represent things which have varying sizes, (i.e. where we would
+ use linked lists in other languages).</p>
+ <p>Erlang does not have a string date type, instead strings can be
+ represented by lists of ASCII characters. So the list
+ <c>[97,98,99]</c> is equivalent to "abc". The Erlang shell is
+ "clever" and guesses the what sort of list we mean and outputs it
+ in what it thinks is the most appropriate form, for example:</p>
+ <pre>
+30> <input>[97,98,99].</input>
+"abc"</pre>
+ </section>
+
+ <section>
+ <title>Standard Modules and Manual Pages</title>
+ <p>Erlang has a lot of standard modules to help you do things. For
+ example, the module <c>io</c> contains a lot of functions to help
+ you do formatted input/output. To look up information about
+ standard modules, the command <c>erl -man</c> can be used at
+ the operating shell or command prompt (i.e. at the same place as
+ that where you started <c>erl</c>). Try the operating system
+ shell command:</p>
+ <pre>
+% <input>erl -man io</input>
+ERLANG MODULE DEFINITION io(3)
+
+MODULE
+ io - Standard I/O Server Interface Functions
+
+DESCRIPTION
+ This module provides an interface to standard Erlang IO
+ servers. The output functions all return ok if they are suc-
+ ...</pre>
+ <p>If this doesn't work on your system, the documentation is
+ included as HTML in the Erlang/OTP release, or you can read
+ the documentation as HTML or download it as PDF from either of
+ the sites www.erlang.se (commercial Erlang) or www.erlang.org
+ (open source), for example for release R9B:</p>
+ <code type="none">
+http://www.erlang.org/doc/r9b/doc/index.html</code>
+ </section>
+
+ <section>
+ <title>Writing Output to a Terminal</title>
+ <p>It's nice to be able to do formatted output in these example, so
+ the next example shows a simple way to use to use
+ the <c>io:format</c> function. Of course, just like all other
+ exported functions, you can test the <c>io:format</c> function in
+ the shell:</p>
+ <pre>
+31> <input>io:format("hello world~n", []).</input>
+hello world
+ok
+32> <input>io:format("this outputs one Erlang term: ~w~n", [hello]).</input>
+this outputs one Erlang term: hello
+ok
+33> <input>io:format("this outputs two Erlang terms: ~w~w~n", [hello, world]).</input>
+this outputs two Erlang terms: helloworld
+ok
+34> <input>io:format("this outputs two Erlang terms: ~w ~w~n", [hello, world]).</input>
+this outputs two Erlang terms: hello world
+ok</pre>
+ <p>The function <c>format/2</c> (i.e. <c>format</c> with two
+ arguments) takes two lists. The first one is nearly always a list
+ written between " ". This list is printed out as it stands,
+ except that each ~w is replaced by a term taken in order from
+ the second list. Each ~n is replaced by a new line.
+ The <c>io:format/2</c> function itself returns the atom <c>ok</c>
+ if everything goes as planned. Like other functions in Erlang, it
+ crashes if an error occurs. This is not a fault in Erlang, it is
+ a deliberate policy. Erlang has sophisticated mechanisms to
+ handle errors which we will show later. As an exercise, try to
+ make <c>io:format</c> crash, it shouldn't be difficult. But
+ notice that although <c>io:format</c> crashes, the Erlang shell
+ itself does not crash.</p>
+ </section>
+
+ <section>
+ <title>A Larger Example</title>
+ <p>Now for a larger example to consolidate what we have learnt so
+ far. Assume we have a list of temperature readings from a number
+ of cities in the world. Some of them are in Celsius (Centigrade)
+ and some in Fahrenheit (as in the previous list). First let's
+ convert them all to Celsius, then let's print out the data neatly.</p>
+ <code type="none">
+%% This module is in file tut5.erl
+
+-module(tut5).
+-export([format_temps/1]).
+
+%% Only this function is exported
+format_temps([])-> % No output for an empty list
+ ok;
+format_temps([City | Rest]) ->
+ print_temp(convert_to_celsius(City)),
+ format_temps(Rest).
+
+convert_to_celsius({Name, {c, Temp}}) -> % No conversion needed
+ {Name, {c, Temp}};
+convert_to_celsius({Name, {f, Temp}}) -> % Do the conversion
+ {Name, {c, (Temp - 32) * 5 / 9}}.
+
+print_temp({Name, {c, Temp}}) ->
+ io:format("~-15w ~w c~n", [Name, Temp]).</code>
+ <pre>
+35> <input>c(tut5).</input>
+{ok,tut5}
+36> <input>tut5:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input>
+<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input>
+moscow -10 c
+cape_town 21.11111111111111 c
+stockholm -4 c
+paris -2.2222222222222223 c
+london 2.2222222222222223 c
+ok</pre>
+ <p>Before we look at how this program works, notice that we have
+ added a few comments to the code. A comment starts with a %
+ character and goes on to the end of the line. Note as well that
+ the <c>-export([format_temps/1]).</c> line only includes
+ the function <c>format_temps/1</c>, the other functions are
+ <em>local</em> functions, i.e. they are not visible from outside
+ the module <c>tut5</c>.</p>
+ <p>Note as well that when testing the program from the shell, I had
+ to spread the input over two lines as the line was too long.</p>
+ <p>When we call <c>format_temps</c> the first time, <c>City</c>
+ gets the value <c>{moscow,{c,-10}}</c> and <c>Rest</c> is
+ the rest of the list. So we call the function
+ <c>print_temp(convert_to_celsius({moscow,{c,-10}}))</c>.</p>
+ <p>Here we see a function call as
+ <c>convert_to_celsius({moscow,{c,-10}})</c> as the argument to
+ the function <c>print_temp</c>. When we <em>nest</em> function
+ calls like this we execute (evaluate) them from the inside out.
+ I.e. we first evaluate <c>convert_to_celsius({moscow,{c,-10}})</c>
+ which gives the value <c>{moscow,{c,-10}}</c> as the temperature
+ is already in Celsius and then we evaluate
+ <c>print_temp({moscow,{c,-10}})</c>. The function
+ <c>convert_to_celsius</c> works in a similar way to
+ the <c>convert_length</c> function in the previous example.</p>
+ <p><c>print_temp</c> simply calls <c>io:format</c> in a similar way
+ to what has been described above. Note that ~-15w says to print
+ the "term" with a field length (width) of 15 and left justify it.
+ (<seealso marker="stdlib:io#fwrite/1">io(3)</seealso>).</p>
+ <p>Now we call <c>format_temps(Rest)</c> with the rest of the list
+ as an argument. This way of doing things is similar to the loop
+ constructs in other languages. (Yes, this is recursion, but don't
+ let that worry you). So the same <c>format_temps</c> function is
+ called again, this time <c>City</c> gets the value
+ <c>{cape_town,{f,70}}</c> and we repeat the same procedure as
+ before. We go on doing this until the list becomes empty, i.e. [],
+ which causes the first clause <c>format_temps([])</c> to match.
+ This simply returns (results in) the atom <c>ok</c>, so
+ the program ends.</p>
+ </section>
+
+ <section>
+ <title>Matching, Guards and Scope of Variables</title>
+ <p>It could be useful to find the maximum and minimum temperature
+ in lists like this. Before extending the program to do this,
+ let's look at functions for finding the maximum value of
+ the elements in a list:</p>
+ <code type="none">
+-module(tut6).
+-export([list_max/1]).
+
+list_max([Head|Rest]) ->
+ list_max(Rest, Head).
+
+list_max([], Res) ->
+ Res;
+list_max([Head|Rest], Result_so_far) when Head > Result_so_far ->
+ list_max(Rest, Head);
+list_max([Head|Rest], Result_so_far) ->
+ list_max(Rest, Result_so_far).</code>
+ <pre>
+37> <input>c(tut6).</input>
+{ok,tut6}
+38> <input>tut6:list_max([1,2,3,4,5,7,4,3,2,1]).</input>
+7</pre>
+ <p>First note that we have two functions here with the same name
+ <c>list_max</c>. However each of these takes a different number
+ of arguments (parameters). In Erlang these are regarded as
+ completely different functions. Where we need to distinguish
+ between these functions we write <c>name/arity</c>, where
+ <c>name</c> is the name of the function and <c>arity</c> is
+ the number of arguments, in this case <c>list_max/1</c> and
+ <c>list_max/2</c>.</p>
+ <p>This is an example where we walk through a list "carrying" a
+ value with us, in this case <c>Result_so_far</c>.
+ <c>list_max/1</c> simply assumes that the max value of the list
+ is the head of the list and calls <c>list_max/2</c> with the rest
+ of the list and the value of the head of the list, in the above
+ this would be <c>list_max([2,3,4,5,7,4,3,2,1],1)</c>. If we tried
+ to use <c>list_max/1</c> with an empty list or tried to use it
+ with something which isn't a list at all, we would cause an error.
+ Note that the Erlang philosophy is not to handle errors of this
+ type in the function they occur, but to do so elsewhere. More
+ about this later.</p>
+ <p>In <c>list_max/2</c> we walk down the list and use <c>Head</c>
+ instead of <c>Result_so_far</c> when <c>Head</c> &gt;
+ <c>Result_so_far</c>. <c>when</c> is a special word we use before
+ the -&gt; in the function to say that we should only use this part
+ of the function if the test which follows is true. We call tests
+ of this type a <em>guard</em>. If the guard isn't true (we say
+ the guard fails), we try the next part of the function. In this
+ case if <c>Head</c> isn't greater than <c>Result_so_far</c> then
+ it must be smaller or equal to is, so we don't need a guard on
+ the next part of the function.</p>
+ <p>Some useful operators in guards are, &lt; less than, &gt;
+ greater than, == equal, &gt;= greater or equal, =&lt; less or
+ equal, /= not equal. (see the chapter
+ <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual).</p>
+ <p>To change the above program to one which works out the minimum
+ value of the element in a list, all we would need to do is to
+ write &lt; instead of &gt;. (But it would be wise to change
+ the name of the function to <c>list_min</c> :-).</p>
+ <p>Remember that I mentioned earlier that a variable could only be
+ given a value once in its scope? In the above we see, for example,
+ that <c>Result_so_far</c> has been given several values. This is
+ OK since every time we call <c>list_max/2</c> we create a new
+ scope and one can regard the <c>Result_so_far</c> as a completely
+ different variable in each scope.</p>
+ <p>Another way of creating and giving a variable a value is by using
+ the match operator = . So if I write <c>M = 5</c>, a variable
+ called <c>M</c> will be created and given the value 5. If, in
+ the same scope I then write <c>M = 6</c>, I'll get an error. Try
+ this out in the shell:</p>
+ <pre>
+39> <input>M = 5.</input>
+5
+40> <input>M = 6.</input>
+** exception error: no match of right hand side value 6
+41> <input>M = M + 1.</input>
+** exception error: no match of right hand side value 6
+42> <input>N = M + 1.</input>
+6</pre>
+ <p>The use of the match operator is particularly useful for pulling
+ apart Erlang terms and creating new ones.</p>
+ <pre>
+43> <input>{X, Y} = {paris, {f, 28}}.</input>
+{paris,{f,28}}
+44> <input>X.</input>
+paris
+45> <input>Y.</input>
+{f,28}</pre>
+ <p>Here we see that <c>X</c> gets the value <c>paris</c> and
+ <c>Y</c><c>{f,28}</c>.</p>
+ <p>Of course if we try to do the same again with another city, we
+ get an error:</p>
+ <pre>
+46> <input>{X, Y} = {london, {f, 36}}.</input>
+** exception error: no match of right hand side value {london,{f,36}}</pre>
+ <p>Variables can also be used to improve the readability of
+ programs, for example, in the <c>list_max/2</c> function above,
+ we could write:</p>
+ <code type="none">
+list_max([Head|Rest], Result_so_far) when Head > Result_so_far ->
+ New_result_far = Head,
+ list_max(Rest, New_result_far);</code>
+ <p>which is possibly a little clearer.</p>
+ </section>
+
+ <section>
+ <title>More About Lists</title>
+ <p>Remember that the | operator can be used to get the head of a
+ list:</p>
+ <pre>
+47> <input>[M1|T1] = [paris, london, rome].</input>
+[paris,london,rome]
+48> <input>M1.</input>
+paris
+49> <input>T1.</input>
+[london,rome]</pre>
+ <p>The | operator can also be used to add a head to a list:</p>
+ <pre>
+50> <input>L1 = [madrid | T1].</input>
+[madrid,london,rome]
+51> <input>L1.</input>
+[madrid,london,rome]</pre>
+ <p>Now an example of this when working with lists - reversing
+ the order of a list:</p>
+ <code type="none">
+-module(tut8).
+
+-export([reverse/1]).
+
+reverse(List) ->
+ reverse(List, []).
+
+reverse([Head | Rest], Reversed_List) ->
+ reverse(Rest, [Head | Reversed_List]);
+reverse([], Reversed_List) ->
+ Reversed_List.</code>
+ <pre>
+52> <input>c(tut8).</input>
+{ok,tut8}
+53> <input>tut8:reverse([1,2,3]).</input>
+[3,2,1]</pre>
+ <p>Consider how <c>Reversed_List</c> is built. It starts as [], we
+ then successively take off the heads of the list to be reversed
+ and add them to the the <c>Reversed_List</c>, as shown in
+ the following:</p>
+ <code type="none">
+reverse([1|2,3], []) =>
+ reverse([2,3], [1|[]])
+
+reverse([2|3], [1]) =>
+ reverse([3], [2|[1])
+
+reverse([3|[]], [2,1]) =>
+ reverse([], [3|[2,1]])
+
+reverse([], [3,2,1]) =>
+ [3,2,1]</code>
+ <p>The module <c>lists</c> contains a lot of functions for
+ manipulating lists, for example for reversing them, so before you
+ write a list manipulating function it is a good idea to check
+ that one isn't already written for you. (see
+ <seealso marker="stdlib:lists">lists(3)</seealso>).</p>
+ <p>Now lets get back to the cities and temperatures, but take a more
+ structured approach this time. First let's convert the whole list
+ to Celsius as follows and test the function:</p>
+ <code type="none">
+-module(tut7).
+-export([format_temps/1]).
+
+format_temps(List_of_cities) ->
+ convert_list_to_c(List_of_cities).
+
+convert_list_to_c([{Name, {f, F}} | Rest]) ->
+ Converted_City = {Name, {c, (F -32)* 5 / 9}},
+ [Converted_City | convert_list_to_c(Rest)];
+
+convert_list_to_c([City | Rest]) ->
+ [City | convert_list_to_c(Rest)];
+
+convert_list_to_c([]) ->
+ [].</code>
+ <pre>
+54> <input>c(tut7).</input>
+{ok, tut7}.
+55> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input>
+<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input>
+[{moscow,{c,-10}},
+ {cape_town,{c,21.11111111111111}},
+ {stockholm,{c,-4}},
+ {paris,{c,-2.2222222222222223}},
+ {london,{c,2.2222222222222223}}]</pre>
+ <p>Looking at this bit by bit:</p>
+ <code type="none">
+format_temps(List_of_cities) ->
+ convert_list_to_c(List_of_cities).</code>
+ <p>Here we see that <c>format_temps/1</c> calls
+ <c>convert_list_to_c/1</c>. <c>convert_list_to_c/1</c> takes off
+ the head of the <c>List_of_cities</c>, converts it to Celsius if
+ needed. The | operator is used to add the (maybe) converted
+ to the converted rest of the list:</p>
+ <code type="none">
+[Converted_City | convert_list_to_c(Rest)];</code>
+ <p>or</p>
+ <code type="none">
+[City | convert_list_to_c(Rest)];</code>
+ <p>We go on doing this until we get to the end of the list (i.e.
+ the list is empty:</p>
+ <code type="none">
+convert_list_to_c([]) ->
+ [].</code>
+ <p>Now we have converted the list, we add a function to print it:</p>
+ <code type="none">
+-module(tut7).
+-export([format_temps/1]).
+
+format_temps(List_of_cities) ->
+ Converted_List = convert_list_to_c(List_of_cities),
+ print_temp(Converted_List).
+
+convert_list_to_c([{Name, {f, F}} | Rest]) ->
+ Converted_City = {Name, {c, (F -32)* 5 / 9}},
+ [Converted_City | convert_list_to_c(Rest)];
+
+convert_list_to_c([City | Rest]) ->
+ [City | convert_list_to_c(Rest)];
+
+convert_list_to_c([]) ->
+ [].
+
+print_temp([{Name, {c, Temp}} | Rest]) ->
+ io:format("~-15w ~w c~n", [Name, Temp]),
+ print_temp(Rest);
+print_temp([]) ->
+ ok.</code>
+ <pre>
+56> <input>c(tut7).</input>
+{ok,tut7}
+57> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input>
+<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input>
+moscow -10 c
+cape_town 21.11111111111111 c
+stockholm -4 c
+paris -2.2222222222222223 c
+london 2.2222222222222223 c
+ok</pre>
+ <p>We now have to add a function to find the cities with
+ the maximum and minimum temperatures. The program below isn't
+ the most efficient way of doing this as we walk through the list
+ of cities four times. But it is better to first strive for
+ clarity and correctness and to make programs efficient only if
+ really needed.</p>
+ <code type="none"><![CDATA[
+-module(tut7).
+-export([format_temps/1]).
+
+format_temps(List_of_cities) ->
+ Converted_List = convert_list_to_c(List_of_cities),
+ print_temp(Converted_List),
+ {Max_city, Min_city} = find_max_and_min(Converted_List),
+ print_max_and_min(Max_city, Min_city).
+
+convert_list_to_c([{Name, {f, Temp}} | Rest]) ->
+ Converted_City = {Name, {c, (Temp -32)* 5 / 9}},
+ [Converted_City | convert_list_to_c(Rest)];
+
+convert_list_to_c([City | Rest]) ->
+ [City | convert_list_to_c(Rest)];
+
+convert_list_to_c([]) ->
+ [].
+
+print_temp([{Name, {c, Temp}} | Rest]) ->
+ io:format("~-15w ~w c~n", [Name, Temp]),
+ print_temp(Rest);
+print_temp([]) ->
+ ok.
+
+find_max_and_min([City | Rest]) ->
+ find_max_and_min(Rest, City, City).
+
+find_max_and_min([{Name, {c, Temp}} | Rest],
+ {Max_Name, {c, Max_Temp}},
+ {Min_Name, {c, Min_Temp}}) ->
+ if
+ Temp > Max_Temp ->
+ Max_City = {Name, {c, Temp}}; % Change
+ true ->
+ Max_City = {Max_Name, {c, Max_Temp}} % Unchanged
+ end,
+ if
+ Temp < Min_Temp ->
+ Min_City = {Name, {c, Temp}}; % Change
+ true ->
+ Min_City = {Min_Name, {c, Min_Temp}} % Unchanged
+ end,
+ find_max_and_min(Rest, Max_City, Min_City);
+
+find_max_and_min([], Max_City, Min_City) ->
+ {Max_City, Min_City}.
+
+print_max_and_min({Max_name, {c, Max_temp}}, {Min_name, {c, Min_temp}}) ->
+ io:format("Max temperature was ~w c in ~w~n", [Max_temp, Max_name]),
+ io:format("Min temperature was ~w c in ~w~n", [Min_temp, Min_name]).]]></code><pre>
+58> <input>c(tut7).</input>
+{ok, tut7}
+59> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input>
+<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input>
+moscow -10 c
+cape_town 21.11111111111111 c
+stockholm -4 c
+paris -2.2222222222222223 c
+london 2.2222222222222223 c
+Max temperature was 21.11111111111111 c in cape_town
+Min temperature was -10 c in moscow
+ok</pre>
+ </section>
+
+ <section>
+ <title>If and Case</title>
+ <p>The function <c>find_max_and_min</c> works out the maximum and
+ minimum temperature. We have introduced a new construct here
+ <c>if</c>. If works as follows:</p>
+ <code type="none">
+if
+ Condition 1 ->
+ Action 1;
+ Condition 2 ->
+ Action 2;
+ Condition 3 ->
+ Action 3;
+ Condition 4 ->
+ Action 4
+end</code>
+ <p>Note there is no ";" before <c>end</c>! Conditions are the same
+ as guards, tests which succeed or fail. Erlang starts at the top
+ until it finds a condition which succeeds and then it evaluates
+ (performs) the action following the condition and ignores all
+ other conditions and action before the <c>end</c>. If no
+ condition matches, there will be a run-time failure. A condition
+ which always is succeeds is the atom, <c>true</c> and this is
+ often used last in an <c>if</c> meaning do the action following
+ the <c>true</c> if all other conditions have failed.</p>
+ <p>The following is a short program to show the workings of
+ <c>if</c>.</p>
+ <code type="none">
+-module(tut9).
+-export([test_if/2]).
+
+test_if(A, B) ->
+ if
+ A == 5 ->
+ io:format("A == 5~n", []),
+ a_equals_5;
+ B == 6 ->
+ io:format("B == 6~n", []),
+ b_equals_6;
+ A == 2, B == 3 -> %i.e. A equals 2 and B equals 3
+ io:format("A == 2, B == 3~n", []),
+ a_equals_2_b_equals_3;
+ A == 1 ; B == 7 -> %i.e. A equals 1 or B equals 7
+ io:format("A == 1 ; B == 7~n", []),
+ a_equals_1_or_b_equals_7
+ end.</code>
+ <p>Testing this program gives:</p>
+ <pre>
+60> <input>c(tut9).</input>
+{ok,tut9}
+61> <input>tut9:test_if(5,33).</input>
+A == 5
+a_equals_5
+62> <input>tut9:test_if(33,6).</input>
+B == 6
+b_equals_6
+63> <input>tut9:test_if(2, 3).</input>
+A == 2, B == 3
+a_equals_2_b_equals_3
+64> <input>tut9:test_if(1, 33).</input>
+A == 1 ; B == 7
+a_equals_1_or_b_equals_7
+65> <input>tut9:test_if(33, 7).</input>
+A == 1 ; B == 7
+a_equals_1_or_b_equals_7
+66> <input>tut9:test_if(33, 33).</input>
+** exception error: no true branch found when evaluating an if expression
+ in function tut9:test_if/2</pre>
+ <p>Notice that <c>tut9:test_if(33,33)</c> did not cause any
+ condition to succeed so we got the run time error
+ <c>if_clause</c>, here nicely formatted by the shell. See the chapter
+ <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual for details
+ of the many guard tests available. <c>case</c> is another
+ construct in Erlang. Recall that we wrote the
+ <c>convert_length</c> function as:</p>
+ <code type="none">
+convert_length({centimeter, X}) ->
+ {inch, X / 2.54};
+convert_length({inch, Y}) ->
+ {centimeter, Y * 2.54}.</code>
+ <p>We could also write the same program as:</p>
+ <code type="none">
+-module(tut10).
+-export([convert_length/1]).
+
+convert_length(Length) ->
+ case Length of
+ {centimeter, X} ->
+ {inch, X / 2.54};
+ {inch, Y} ->
+ {centimeter, Y * 2.54}
+ end.</code>
+ <pre>
+67> <input>c(tut10).</input>
+{ok,tut10}
+68> <input>tut10:convert_length({inch, 6}).</input>
+{centimeter,15.24}
+69> <input>tut10:convert_length({centimeter, 2.5}).</input>
+{inch,0.984251968503937}</pre>
+ <p>Notice that both <c>case</c> and <c>if</c> have <em>return values</em>, i.e. in the above example <c>case</c> returned
+ either <c>{inch,X/2.54}</c> or <c>{centimeter,Y*2.54}</c>.
+ The behaviour of <c>case</c> can also be modified by using guards.
+ An example should hopefully clarify this. The following example
+ tells us the length of a month, given the year. We need to know
+ the year of course, since February has 29 days in a leap year.</p>
+ <code type="none">
+-module(tut11).
+-export([month_length/2]).
+
+month_length(Year, Month) ->
+ %% All years divisible by 400 are leap
+ %% Years divisible by 100 are not leap (except the 400 rule above)
+ %% Years divisible by 4 are leap (except the 100 rule above)
+ Leap = if
+ trunc(Year / 400) * 400 == Year ->
+ leap;
+ trunc(Year / 100) * 100 == Year ->
+ not_leap;
+ trunc(Year / 4) * 4 == Year ->
+ leap;
+ true ->
+ not_leap
+ end,
+ case Month of
+ sep -> 30;
+ apr -> 30;
+ jun -> 30;
+ nov -> 30;
+ feb when Leap == leap -> 29;
+ feb -> 28;
+ jan -> 31;
+ mar -> 31;
+ may -> 31;
+ jul -> 31;
+ aug -> 31;
+ oct -> 31;
+ dec -> 31
+ end.</code>
+ <pre>
+70> <input>c(tut11).</input>
+{ok,tut11}
+71> <input>tut11:month_length(2004, feb).</input>
+29
+72> <input>tut11:month_length(2003, feb).</input>
+28
+73> <input>tut11:month_length(1947, aug).</input>
+31</pre>
+ </section>
+
+ <section>
+ <title>Built In Functions (BIFs)</title>
+ <p>Built in functions BIFs are functions which for some reason is
+ built in to the Erlang virtual machine. BIFs often implement
+ functionality that is impossible to implement in Erlang or is to
+ inefficient to implement in Erlang. Some BIFs can be called
+ by use of the function name only but they are by default belonging
+ to the erlang module so for example the call to the BIF <c>trunc</c>
+ below is equivalent with a call to <c>erlang:trunc</c>.</p>
+ <p>As you can see, we first find out if a year is leap or not. If a
+ year is divisible by 400, it is a leap year. To find this out we
+ first divide the year by 400 and use the built in function
+ <c>trunc</c> (more later) to cut off any decimals. We then
+ multiply by 400 again and see if we get back the same value. For
+ example, year 2004:</p>
+ <code type="none">
+2004 / 400 = 5.01
+trunc(5.01) = 5
+5 * 400 = 2000</code>
+ <p>and we can see that we got back 2000 which is not the same as
+ 2004, so 2004 isn't divisible by 400. Year 2000:</p>
+ <code type="none">
+2000 / 400 = 5.0
+trunc(5.0) = 5
+5 * 400 = 2000</code>
+ <p>so we have a leap year. The next two tests if the year is
+ divisible by 100 or 4 are done in the same way. The first
+ <c>if</c> returns <c>leap</c> or <c>not_leap</c> which lands up
+ in the variable <c>Leap</c>. We use this variable in the guard
+ for <c>feb</c> in the following <c>case</c> which tells us how
+ long the month is.</p>
+ <p>This example showed the use of <c>trunc</c>, an easier way would
+ be to use the Erlang operator <c>rem</c> which gives the remainder
+ after division. For example:</p>
+ <pre>
+74> <input>2004 rem 400.</input>
+4</pre>
+ <p>so instead of writing</p>
+ <code type="none">
+trunc(Year / 400) * 400 == Year ->
+ leap;</code>
+ <p>we could write</p>
+ <code type="none">
+Year rem 400 == 0 ->
+ leap;</code>
+ <p>There are many other built in functions (BIF) such as
+ <c>trunc</c>. Only a few built in functions can be used in guards,
+ and you cannot use functions you have defined yourself in guards.
+ (see the chapter
+ <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual) (Aside for
+ advanced readers: This is to ensure that guards don't have side
+ effects). Let's play with a few of these functions in the shell:</p>
+ <pre>
+75> <input>trunc(5.6).</input>
+5
+76> <input>round(5.6).</input>
+6
+77> <input>length([a,b,c,d]).</input>
+4
+78> <input>float(5).</input>
+5.0
+79> <input>is_atom(hello).</input>
+true
+80> <input>is_atom("hello").</input>
+false
+81> <input>is_tuple({paris, {c, 30}}).</input>
+true
+82> <input>is_tuple([paris, {c, 30}]).</input>
+false</pre>
+ <p>All the above can be used in guards. Now for some which can't be
+ used in guards:</p>
+ <pre>
+83> <input>atom_to_list(hello).</input>
+"hello"
+84> <input>list_to_atom("goodbye").</input>
+goodbye
+85> <input>integer_to_list(22).</input>
+"22"</pre>
+ <p>The 3 BIFs above do conversions which would be difficult (or
+ impossible) to do in Erlang.</p>
+ </section>
+
+ <section>
+ <title>Higher Order Functions (Funs)</title>
+ <p>Erlang, like most modern functional programming languages, has
+ higher order functions. We start with an example using the shell:</p>
+ <pre>
+86> <input>Xf = fun(X) -> X * 2 end.</input>
+#Fun&lt;erl_eval.5.123085357&gt;
+87> <input>Xf(5).</input>
+10</pre>
+ <p>What we have done here is to define a function which doubles
+ the value of number and assign this function to a variable. Thus
+ <c>Xf(5)</c> returned the value 10. Two useful functions when
+ working with lists are <c>foreach</c> and <c>map</c>, which are
+ defined as follows:</p>
+ <code type="none">
+foreach(Fun, [First|Rest]) ->
+ Fun(First),
+ foreach(Fun, Rest);
+foreach(Fun, []) ->
+ ok.
+
+map(Fun, [First|Rest]) ->
+ [Fun(First)|map(Fun,Rest)];
+map(Fun, []) ->
+ [].</code>
+ <p>These two functions are provided in the standard module
+ <c>lists</c>. <c>foreach</c> takes a list and applies a fun to
+ every element in the list, <c>map</c> creates a new list by
+ applying a fun to every element in a list. Going back to
+ the shell, we start by using <c>map</c> and a fun to add 3 to
+ every element of a list:</p>
+ <pre>
+88> <input>Add_3 = fun(X) -> X + 3 end.</input>
+#Fun&lt;erl_eval.5.123085357&gt;
+89> <input>lists:map(Add_3, [1,2,3]).</input>
+[4,5,6]</pre>
+ <p>Now lets print out the temperatures in a list of cities (yet
+ again):</p>
+ <pre>
+90> <input>Print_City = fun({City, {X, Temp}}) -> io:format("~-15w ~w ~w~n",</input>
+<input>[City, X, Temp]) end.</input>
+#Fun&lt;erl_eval.5.123085357&gt;
+91> <input>lists:foreach(Print_City, [{moscow, {c, -10}}, {cape_town, {f, 70}},</input>
+<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input>
+moscow c -10
+cape_town f 70
+stockholm c -4
+paris f 28
+london f 36
+ok</pre>
+ <p>We will now define a fun which can be used to go through a list
+ of cities and temperatures and transform them all to Celsius.</p>
+ <code type="none">
+-module(tut13).
+
+-export([convert_list_to_c/1]).
+
+convert_to_c({Name, {f, Temp}}) ->
+ {Name, {c, trunc((Temp - 32) * 5 / 9)}};
+convert_to_c({Name, {c, Temp}}) ->
+ {Name, {c, Temp}}.
+
+convert_list_to_c(List) ->
+ lists:map(fun convert_to_c/1, List).</code>
+ <pre>
+92> <input>tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},</input>
+<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input>
+[{moscow,{c,-10}},
+ {cape_town,{c,21}},
+ {stockholm,{c,-4}},
+ {paris,{c,-2}},
+ {london,{c,2}}]</pre>
+ <p>The <c>convert_to_c</c> function is the same as before, but we
+ use it as a fun:</p>
+ <code type="none">
+lists:map(fun convert_to_c/1, List)</code>
+ <p>When we use a function defined elsewhere as a fun we can refer
+ to it as <c>Function/Arity</c> (remember that <c>Arity</c> =
+ number of arguments). So in the <c>map</c> call we write
+ <c>lists:map(fun convert_to_c/1, List)</c>. As you can see
+ <c>convert_list_to_c</c> becomes much shorter and easier to
+ understand.</p>
+ <p>The standard module <c>lists</c> also contains a function
+ <c>sort(Fun, List)</c> where <c>Fun</c> is a fun with two
+ arguments. This fun should return <c>true</c> if the the first
+ argument is less than the second argument, or else <c>false</c>.
+ We add sorting to the <c>convert_list_to_c</c>:</p>
+ <code type="none"><![CDATA[
+-module(tut13).
+
+-export([convert_list_to_c/1]).
+
+convert_to_c({Name, {f, Temp}}) ->
+ {Name, {c, trunc((Temp - 32) * 5 / 9)}};
+convert_to_c({Name, {c, Temp}}) ->
+ {Name, {c, Temp}}.
+
+convert_list_to_c(List) ->
+ New_list = lists:map(fun convert_to_c/1, List),
+ lists:sort(fun({_, {c, Temp1}}, {_, {c, Temp2}}) ->
+ Temp1 < Temp2 end, New_list).]]></code>
+ <pre>
+93> <input>c(tut13).</input>
+{ok,tut13}
+94> <input>tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},</input>
+<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input>
+[{moscow,{c,-10}},
+ {stockholm,{c,-4}},
+ {paris,{c,-2}},
+ {london,{c,2}},
+ {cape_town,{c,21}}]</pre>
+ <p>In <c>sort</c> we use the fun:</p>
+ <code type="none"><![CDATA[
+fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> Temp1 < Temp2 end,]]></code>
+ <p>Here we introduce the concept of an <em>anonymous variable</em>
+ "_". This is simply shorthand for a variable which is going to
+ get a value, but we will ignore the value. This can be used
+ anywhere suitable, not just in fun's. <c><![CDATA[Temp1 < Temp2]]></c>
+ returns <c>true</c> if <c>Temp1</c> is less than <c>Temp2</c>.</p>
+ </section>
+</chapter>
+
diff --git a/system/doc/getting_started/xmlfiles.mk b/system/doc/getting_started/xmlfiles.mk
new file mode 100644
index 0000000000..c784d79dc3
--- /dev/null
+++ b/system/doc/getting_started/xmlfiles.mk
@@ -0,0 +1,24 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+GETTING_STARTED_CHAPTER_FILES = \
+ conc_prog.xml \
+ intro.xml \
+ records_macros.xml \
+ robustness.xml \
+ seq_prog.xml