diff options
Diffstat (limited to 'system/doc/getting_started')
-rw-r--r-- | system/doc/getting_started/conc_prog.xml | 350 | ||||
-rw-r--r-- | system/doc/getting_started/intro.xml | 63 | ||||
-rw-r--r-- | system/doc/getting_started/records_macros.xml | 88 | ||||
-rw-r--r-- | system/doc/getting_started/robustness.xml | 145 | ||||
-rw-r--r-- | system/doc/getting_started/seq_prog.xml | 823 |
5 files changed, 759 insertions, 710 deletions
diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml index 2b64826a93..0dd9efb363 100644 --- a/system/doc/getting_started/conc_prog.xml +++ b/system/doc/getting_started/conc_prog.xml @@ -29,25 +29,26 @@ <file>conc_prog.xml</file> </header> + <marker id="Distributed Programming"></marker> <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 + and distributed programming. By concurrency is meant programs + that can handle several threads of execution at the same time. + For example, modern operating systems allow you to use a + word processor, a spreadsheet, a mail client, and a print job all + running at the same time. 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 + time, but it swaps between the jobs at 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> + create parallel threads of execution in an Erlang program and + to allow these threads to communicate with each other. In + Erlang, each thread of execution is called 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> + share no data, that is why they are called 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> @@ -73,14 +74,14 @@ 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> + <p>As shown, the function <c>say_something</c> writes its first + argument the number of times specified by second argument. + The function <c>start</c> starts two Erlang processes, + one that writes "hello" three times and one that writes + "goodbye" three times. Both processes use the function + <c>say_something</c>. Notice that a function used in this way by + <c>spawn</c>, to start a process, must be exported from the module + (that is, in the <c>-export</c> at the start of the module).</p> <pre> 9> <input>tut14:start().</input> hello @@ -90,19 +91,19 @@ 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", + <p>Notice that it did not write "hello" three times and then + "goodbye" three times. Instead, the first process wrote a "hello", the second a "goodbye", the first another "hello" and so forth. But where did the <0.63.0> 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> + function is 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 <0.63.0> - 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 + is the pid of the <c>spawn</c> function call above. + The next example shows how to use pids.</p> + <p>Notice also that ~p is used 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 @@ -112,8 +113,8 @@ spawn(tut14, say_something, [goodbye, 3]).</code> <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> + <p>In the following example two processes are created and + they send messages to each other a number of times.</p> <code type="none"> -module(tut15). @@ -157,13 +158,13 @@ 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> + <p>The function <c>start</c> first creates a process, + let us 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> + <c>start</c> now creates another process "ping":</p> <code type="none"> spawn(tut15, ping, [3, Pong_PID]),</code> <p>This process executes:</p> @@ -181,7 +182,7 @@ receive 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> + for messages from other processes. It has the following format:</p> <code type="none"> receive pattern1 -> @@ -192,35 +193,37 @@ receive patternN actionsN end.</code> - <p>Note: no ";" before the <c>end</c>.</p> + <p>Notice there is 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> + That is, they can be lists, tuples, integers, atoms, pids, + and so on.</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 + 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> + the actions corresponding to 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 + 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, + If the second pattern does not match, the third is tried and so on + until there are no more patterns to test. If there are no more + patterns to test, the first message is kept in the queue and + the second message is tried 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 + messages in the queue). If the second message does not match, + the third message is tried, and so on, until the end of + the queue is reached. If the end of the queue is reached, + 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 + <p>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 + 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"> @@ -229,20 +232,20 @@ end.</code> <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 + <p>Notice 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 + <p>That is, <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 + get back to the <c>receive</c> again and wait for another message.</p> + <p>Now let us 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 + <p>Looking at the function <c>ping/2</c>, 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 @@ -250,9 +253,9 @@ tut15:ping(3, Pong_PID)</code> <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 + <p><c>self()</c> returns the pid of the process that 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 + for "pong", this lands 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"> @@ -260,37 +263,37 @@ receive pong -> io:format("Ping received pong~n", []) end,</code> - <p>and writes "Ping received pong" when this reply arrives, after + <p>It 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> + is 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 + the output. "Ping" then 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 + <p>In the above example, "pong" was first created to be able + to give the identity of "pong" when "ping" was started. That is, in + some way "ping" must be able to know the identity of "pong" to be + able to send a message to it. Sometimes processes + which need to know each other's identities are started 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 + <p>Let us now rewrite the ping pong example using this and give the name <c>pong</c> to the "pong" process:</p> <code type="none"> -module(tut16). @@ -335,52 +338,57 @@ Pong received ping Ping received pong ping finished Pong finished</pre> - <p>In the <c>start/0</c> function,</p> + <p>Here 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> + In the "ping" process, messages can be sent 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> + <p><c>ping/2</c> now becomes <c>ping/1</c> as + the argument <c>Pong_PID</c> is not needed.</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 + <p>Let us rewrite the ping pong program with "ping" and "pong" + on different computers. First a few things + are needed 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. 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 one line with - the same atom. For example, on Linux or Unix in the OS shell:</p> + directory on all machines on which you are going to run + Erlang systems communicating with each other: + </p> + <list type="bulleted"> + <item>On Windows systems the home directory is the directory + pointed out by the environment variable $HOME - you may need + to set this.</item> + <item> 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.</item> + </list> + <p>The <c>.erlang.cookie</c> file is to contain a 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 + <p>The <c>chmod</c> above makes 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, e.g.: </p> + <p>When you start an Erlang system that is going to talk to other + Erlang systems, you must give it a name, for example:</p> <pre> $ <input>erl -sname my_name</input></pre> <p>We will see more details of this later. 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> + system running on a computer is called an <em>Erlang node</em>.</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 @@ -420,10 +428,10 @@ start_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 + <p>Let us assume there are two computers called gollum and kosken. + First a node is started on kosken, called ping, and then a node on gollum, called pong.</p> - <p>On kosken (on a Linux/Unix system):</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] @@ -437,12 +445,12 @@ 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> + <p>Now the "pong" process on gollum is started:</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 + <p>And the "ping" process on kosken is started (from the code above you + can 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> @@ -451,8 +459,7 @@ 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> + <p>As shown, the ping pong program has run. On the "pong" side:</p> <pre> (pong@gollum)2> Pong received ping @@ -460,28 +467,28 @@ 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> + <p>Looking at the <c>tut17</c> code, you see that the <c>pong</c> + function itself is unchanged, the following lines work in the same way + irrespective of on which node the "ping" process is executes:</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 + <p>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 disregarding + if the process is on the same node or on a different node.</p> + <p>A difference is how messages are sent 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 + <p>A tuple <c>{registered_name,node_name}</c> is used instead of just the <c>registered_name</c>.</p> - <p>In the previous example, we started "ping" and "pong" from + <p>In the previous example, "ping" and "pong" were started 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> + used to start processes in other nodes.</p> + <p>The next example is the ping pong program, yet again, + but this time "ping" is started in another node:</p> <code type="none"> -module(tut18). @@ -513,7 +520,7 @@ 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> + process) has already been started on kosken, then on gollum this is done:</p> <pre> (pong@gollum)1> <input>tut18:start(ping@kosken).</input> <3934.39.0> @@ -525,39 +532,40 @@ 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 + <p>Notice that all the output is received on gollum. This is because + the I/O 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 + <p>Now for a larger example with a simple + "messenger". The messenger is a program that 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> + <p>Before starting, notice 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> + <p>This example only shows the message passing logic - no + attempt has been made to provide a nice graphical user + interface, although this can also be done in Erlang.</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> + <p>This sort of problem can be solved easier by use of + the facilities in OTP, which also provide methods for + updating code on the fly and so on (see + <seealso marker="doc/design_principles:des_princ#otp design principles"> + OTP Design Principles</seealso>).</p> </item> <item> - <p>The first program we write will contain some inadequacies - regarding the handling of nodes which disappear. We will correct - these in a later version of the program.</p> + <p>The first program contains some inadequacies + regarding handling of nodes which disappear. + These are corrected 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 + <p>The messenger is set up by allowing "clients" to connect to + a central server and say who and where they are. That is, a user + does not 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> @@ -728,19 +736,19 @@ await_result() -> {messenger, What} -> % Normal response io:format("~p~n", [What]) end.</code> - <p>To use this program you need to:</p> + <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> + <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 + <p>In the following example using this program, + nodes are started on four different computers. If you do not have that + many machines available on your network, you can start several nodes on the same machine.</p> - <p>We start up four Erlang nodes: messenger@super, c1@bilbo, + <p>Four Erlang nodes are started up: messenger@super, c1@bilbo, c2@kosken, c3@gollum.</p> - <p>First we start up a the server at messenger@super:</p> + <p>First the server at messenger@super is started up:</p> <pre> (messenger@super)1> <input>messenger:start_server().</input> true</pre> @@ -754,7 +762,7 @@ logged_on</pre> (c2@kosken)1> <input>messenger:logon(james).</input> true logged_on</pre> - <p>and Fred logs on at c3@gollum:</p> + <p>And Fred logs on at c3@gollum:</p> <pre> (c3@gollum)1> <input>messenger:logon(fred).</input> true @@ -764,7 +772,7 @@ logged_on</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 + <p>Fred receives the message and sends a message to Peter and logs off:</p> <pre> Message from peter: "hello" @@ -779,27 +787,28 @@ logoff</pre> 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>First let us look at some of the new concepts that have + been 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, via <c>server(User_List)</c>, and thus creates a loop. + <p>Notice how to write the <c>server</c> function so that it calls + itself, through <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 + this only works if there is no code after the call. Otherwise, + the compiler expects 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 from the <c>lists</c> module. This is a very + <p>Functions in the <c>lists</c> module are used. 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> + <c>Key</c>, 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 @@ -812,82 +821,83 @@ false</pre> [{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> + <p>There are many very useful functions in the <c>lists</c> module.</p> - <p>An Erlang process will (conceptually) run until it does a + <p>An Erlang process (conceptually) runs 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 + in the message queue. "conceptually" is used here 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 + that is, the last function it calls simply returns and does not 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 + special meaning, which is discussed later. In this example, + <c>exit(normal)</c> is done, 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> + process of name <c>RegisteredName</c> exists. If it exists, the pid of + that process is returned. If it does not exist, the atom + <c>undefined</c> is returned.</p> + <p>You should by now be able to understand most of the code in the + messenger-module. Let us study one case in detail: 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> + <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>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> + <p>This 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 + <p>If <c>keysearch</c> returns the atom <c>false</c>, some 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 + <p>This 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> + <c>{value,{From,Name}}</c> it is certain that the user is logged on and + that his name (peter) is in variable <c>Name</c>.</p> + <p>Let us 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> + <p>Notice that as this is <c>server_transfer/5</c>, it is not the same + as the previous function <c>server_transfer/4</c>. Another + <c>keysearch</c> is done 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> + <p>This time argument 2 is used, which is the second element in + the tuple. If this returns the atom <c>false</c>, + fred is not logged on and the following message is sent:</p> <code type="none"> From ! {messenger, receiver_not_found};</code> - <p>which is received by the client, if <c>keysearch</c> returns:</p> + <p>This is received by the client.</p> + <p> If <c>keysearch</c> returns:</p> <code type="none"> {value, {ToPid, fred}}</code> - <p>we send the message:</p> + <p>The following message is sent to fred's client:</p> <code type="none"> ToPid ! {message_from, peter, "hello"}, </code> - <p>to fred's client and the message:</p> + <p>The following message is sent to peter's client:</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 + <p>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 index e8d568bcaf..f9a56e4322 100644 --- a/system/doc/getting_started/intro.xml +++ b/system/doc/getting_started/intro.xml @@ -18,7 +18,7 @@ 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> @@ -28,38 +28,47 @@ <rev></rev> <file>intro.xml</file> </header> + <marker id="getting started"></marker> + + <p>This section is a quick start tutorial to get you started with Erlang. + Everything in this section is true, but only part of the truth. For example, + only the simplest form of the syntax is shown, not all esoteric forms. + Also, parts that are greatly simplified are indicated with *manual*. + This means that a lot more information on the subject is to be found in + the Erlang book or in + <seealso marker="doc/reference_manual:introduction#erlang ref manual"> + Erlang Reference Manual</seealso>.</p> <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> + <title>Prerequisites</title> + + <p>The reader of this section is assumed to be familiar with the following:</p> + <list type="bulleted"> + <item>Computers in general</item> + <item>Basics on how computers are programmed</item> + </list> + </section> <section> - <title>Things Left Out</title> - <p>In particular the following has been omitted:</p> + <title>Omitted Topics</title> + + <p>The following topics are not treated in this section:</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> + <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 software + written in other languages (ports); + this is described in + <seealso marker="doc/tutorial:introduction#interoperability tutorial"> + Interoperability Tutorial</seealso>.</item> + <item>Erlang libraries (for example, file handling).</item> + <item>OTP and (in consequence) the Mnesia database.</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/records_macros.xml b/system/doc/getting_started/records_macros.xml index 73c8ce5c8d..bec751fea2 100644 --- a/system/doc/getting_started/records_macros.xml +++ b/system/doc/getting_started/records_macros.xml @@ -29,27 +29,32 @@ <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> + 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> + <p>To illustrate this, the messenger example from + the previous section is divided into the following five files:</p> + <list type="bulleted"> + <item> + <p><c>mess_config.hrl</c></p> + <p>Header file for configuration data</p></item> + <item> + <p><c>mess_interface.hrl</c></p> + <p>Interface definitions between the client and the messenger</p></item> + <item> + <p><c>user_interface.erl</c></p> + <p>Functions for the user interface</p></item> + <item> + <p><c>mess_client.erl</c></p> + <p>Functions for the client side of the messenger</p></item> + <item> + <p><c>mess_server.erl</c></p> + <p>Functions for the server side of the messenger</p></item> + </list> + <p>While doing this, the message passing interface between the shell, + the client, and the server is cleaned up and is defined + using <em>records</em>. Also, <em>macros</em> are introduced:</p> <code type="none"> %%%----FILE mess_config.hrl---- @@ -244,14 +249,14 @@ server_transfer(From, Name, To, Message, User_List) -> <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> + <p>As shown above, some files have extension <c>.hrl</c>. These + are header files that 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 + <p>In the 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> @@ -265,64 +270,63 @@ server_transfer(From, Name, To, Message, User_List) -> <p>For example:</p> <code type="none"> -record(message_to,{to_name, message}).</code> - <p>This is exactly equivalent to:</p> + <p>This is equivalent to:</p> <code type="none"> {message_to, To_Name, Message}</code> - <p>Creating record, is best illustrated by an example:</p> + <p>Creating a record is best illustrated by an example:</p> <code type="none"> #message_to{message="hello", to_name=fred)</code> - <p>This will create:</p> + <p>This creates:</p> <code type="none"> {message_to, fred, "hello"}</code> - <p>Note that you don't have to worry about the order you assign + <p>Notice that you do not 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 + interfaces that are easy to change. For example, if you want to + add a new field to the record, you 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> + a record, it gets the value of the atom <c>undefined</c>. (*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> + <p>This 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. + <p>Another thing that has been 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> + <p>This file is included in <c>mess_server.erl</c>:</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> + is now replaced by <c>messenger@super</c>.</p> + <p>A macro is also used when spawning 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 + <p>This is a standard macro (that is, defined by the system, not by + the user). <c>?MODULE</c> is always replaced by the name of the + current module (that is, 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> + 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). + when they are referred to during execution of the code. In this + case, they are simply put in our current working directory + (that is, the place you 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> + what the message being sent is. It can be any valid Erlang term.</p> </section> </chapter> diff --git a/system/doc/getting_started/robustness.xml b/system/doc/getting_started/robustness.xml index e8fb81d5e8..82fe0cbc4f 100644 --- a/system/doc/getting_started/robustness.xml +++ b/system/doc/getting_started/robustness.xml @@ -28,27 +28,27 @@ <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>Several things are wrong with the messenger example in + <seealso marker="conc_prog#ex">A Larger Example</seealso>. + For example, if a node where a user is logged + on goes down without doing a logoff, the user remains in + the server's <c>User_List</c>, but the client disappears. This + makes it impossible for the user to log on again as the server + thinks the user already is 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 + message, leaving the sending client hanging forever in the <c>await_result</c> function?</p> <section> - <title>Timeouts</title> - <p>Before improving the messenger program we will look into some + <title>Time-outs</title> + <p>Before improving the messenger program, let us look at 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> + so that "pong" can 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>time-out</em> to <c>pong</c> as shown in the following example:</p> <code type="none"> -module(tut19). @@ -80,9 +80,9 @@ start_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> + <p>After this is compiled and the file <c>tut19.beam</c> + is copied to the necessary directories, the following is seen + on (pong@kosken): </p> <pre> (pong@kosken)1> <input>tut19:start_pong().</input> true @@ -90,7 +90,7 @@ Pong received ping Pong received ping Pong received ping Pong timed out</pre> - <p>On (ping@gollum):</p> + <p>And the following is seen on (ping@gollum):</p> <pre> (ping@gollum)1> <input>tut19:start_ping(pong@kosken).</input> <0.36.0> @@ -98,7 +98,7 @@ Ping received pong Ping received pong Ping received pong ping finished </pre> - <p>(The timeout is set in:</p> + <p>The time-out is set in:</p> <code type="none"> pong() -> receive @@ -109,35 +109,36 @@ 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> + <p>The time-out (<c>after 5000</c>) is started when + <c>receive</c> is entered. + The time-out 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 + the actions following the time-out are 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> + that is, preceded by all other message reception specifications in + the <c>receive</c>. It is also possible to call a function that + returned an integer for the time-out:</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 + <p>In general, there are better ways than using time-outs to + supervise parts of a distributed Erlang system. Time-outs 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> + specified time. For example, a time-out can be used to log a user + out of the messenger system if they have not accessed it for, + say, 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, + <p>Before going into details of the supervision and error handling + in an Erlang system, let us 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 + <p>A process which encounters a runtime error (for example, divide by zero, + bad match, trying to call a function that does not exist and so on) + exits with an error, that is, 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 @@ -151,18 +152,23 @@ after pong_timeout() -></code> 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 + <p>The default behaviour of a process that 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 + <p>The default behaviour in the two other cases (that is, abnormal exit) + above is to:</p> + <list type="bulleted"> + <item>Bypass all messages to the receiving process.</item> + <item>Kill the receiving process.</item> + <item>Propagate the same error signal to the links of the + killed process.</item> + </list> + <p>In this way you can connect all processes in a + transaction together using links. If one of the processes + exits abnormally, all the processes in the transaction are + killed. As it is often wanted 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 + that 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> @@ -208,13 +214,13 @@ 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 + and the "ping" process can be spawned on a separate node. Notice 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> + <c>exit(ping)</c> when it finishes and this causes an exit + signal to be sent to "pong", which also terminates.</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 with + signals. Instead, all signals are turned into normal messages on the format <c>{'EXIT',FromPID,Reason}</c> and added to the end of the receiving process' message queue. This behaviour is set by:</p> <code type="none"> @@ -223,8 +229,8 @@ process_flag(trap_exit, true)</code> <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 + the supervisory programs in OTP. + However, the ping pong program is modified to illustrate exit trapping.</p> <code type="none"> -module(tut21). @@ -277,7 +283,7 @@ pong exiting, got {'EXIT',<3820.39.0>,ping}</pre> <section> <title>The Larger Example with Robustness Added</title> - <p>Now we return to the messenger program and add changes which + <p>Let us return to the messenger program and add changes to make it more robust:</p> <code type="none"> %%% Message passing utility. @@ -449,35 +455,34 @@ await_result() -> io:format("No response from server~n", []), exit(timeout) end.</code> - <p>We have added the following changes:</p> + <p>The following changes are added:</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> + <c>{'EXIT',From,Reason}</c>, this means that a client process has + terminated or is unreachable for one of the following reasons:</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> + <item>The user has logged off (the "logoff" + message is removed).</item> + <item>The network connection to the client is broken.</item> + <item>The node on which the client process resides has gone down.</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 + <p>If an exit signal is received as above, the tuple + <c>{From,Name}</c> is deleted 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: + the system) is 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 + <p>Also, a time-out of five seconds has been introduced in + the <c>await_result</c> function. That is, 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 + is only needed in the logon sequence before the client and the server are linked.</p> - <p>An interesting case is if the client was to terminate before + <p>An interesting case is if the client terminates 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> + <c>{'EXIT',From,noproc}</c>, to be automatically generated. This is + 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 index 699b9487ed..5d96aed8d4 100644 --- a/system/doc/getting_started/seq_prog.xml +++ b/system/doc/getting_started/seq_prog.xml @@ -31,11 +31,15 @@ <section> <title>The Erlang Shell</title> - <p>Most operating systems have a command interpreter or shell- Unix - and Linux have many, while 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 + <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 bits of Erlang code can be written directly, + and be evaluated to see what happens + (see the <seealso marker="stdlib:shell">shell(3)</seealso> + manual page in STDLIB). + </p> + <p>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> @@ -45,41 +49,39 @@ Erlang R15B (erts-5.9.1) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe] [ker Eshell V5.9.1 (abort with ^G) 1></pre> - <p>Now type in "2 + 5." as shown below.</p> + <p>Type "2 + 5." in the shell and then press Enter (carriage return). + Notice that you tell the shell you are done entering code by finishing + with a full stop "." and a carriage return.</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> 2>) 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> + <p>As shown, the Erlang shell numbers the lines that + can be entered, (as 1> 2>) and that it correctly says + that 2 + 5 is 7. If you make writing mistakes in the shell, + you can delete with the backspace key, as in most shells. + There are many more editing commands in the shell + (see <seealso marker="erts:tty">tty - A command line interface</seealso> in ERTS User's Guide).</p> + <p>(Notice that many line numbers given by the shell in the + following examples are out of sequence. This is because this + tutorial was written and code-tested in separate sessions).</p> + <p>Here is a bit 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> + <p>Notice the use of brackets, the multiplication operator "*", + and the division operator "/", as in normal arithmetic (see + <seealso marker="doc/reference_manual:expressions">Expressions</seealso>).</p> + <p>Press Control-C to shut down the Erlang system and the Erlang + shell.</p> + <p>The following output is shown:</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 + <p>Another way to shut down the Erlang system is by entering <c>halt()</c>:</p> <pre> 3> <input>halt().</input> @@ -88,67 +90,70 @@ BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded <section> <title>Modules and Functions</title> - <p>A programming language isn't much use if you can just run code + <p>A programming language is not much use if you only can 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> + a file named <c>tut.erl</c> using a suitable + text editor. The file name <c>tut.erl</c> is important, and also + that it is in the same directory as the one where you started + <c>erl</c>). If you are lucky your editor has an Erlang mode + that makes it easier for you to enter and format your code + nicely (see <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 is 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> + <p>It is not hard to guess that this program doubles the value of + numbers. The first two lines of the code are described later. + Let us compile the program. This can be done in an Erlang shell + as follows, where <c>c</c> means compile:</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 let's run the program.</p> + <p>The <c>{ok,tut}</c> means that the compilation is OK. If it + says "error" it means that there is some mistake in the text + that you entered. Additional error messages gives an idea to + what is wrong so you can modify the text and then try to compile + the program again.</p> + <p>Now 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> + <p>As expected, double of 10 is 20.</p> + <p>Now let us get back to the first two lines of the code. Erlang + programs are + written in files. Each file contains an Erlang + <em>module</em>. The first line of code in the module is + the module name (see + <seealso marker="doc/reference_manual:modules">Modules</seealso>):</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 + <p>Thus, the module is called <em>tut</em>. Notice + the full stop "." 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> + the extension ".erl". In this case the file name is <c>tut.erl</c>. + When using a function in another module, the syntax + <c>module_name:function_name(arguments)</c> is used. So the + following means call function <c>double</c> in module <c>tut</c> + with argument "10".</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> + <p>The second line says that the module <c>tut</c> contains a + function called <c>double</c>, which takes one argument + (<c>X</c> in our example):</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> + <p>The second line also says that this function can be called from + outside the module <c>tut</c>. More about this later. Again, + notice the "." at the end of the line.</p> + <p>Now for a more complicated example, the factorial of a number. + For example, the factorial of 4 is 4 * 3 * 2 * 1, which equals 24.</p> + <p>Enter the following code in a file named <c>tut1.erl</c>:</p> <code type="none"> -module(tut1). -export([fac/1]). @@ -157,30 +162,34 @@ 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> + <p>So this is a module, called <c>tut1</c> that contains a + function called <c>fac></c>, which takes one argument, + <c>N</c>.</p> + <p>The first part says that the factorial of 1 is 1.:</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> + <p>Notice that this part ends with a semicolon ";" that indicates + that there is more of the function <c>fac></c> to come.</p> + <p>The second part says that the factorial of N is N multiplied + by the factorial of N - 1:</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 + <p>Notice 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> + <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>Here the function <c>fac></c> in module <c>tut1</c> is called + with argument <c>4</c>.</p> + <p>A function can have many arguments. Let us expand the module + <c>tut1</c> with the function to multiply two numbers:</p> <code type="none"> -module(tut1). -export([fac/1, mult/2]). @@ -192,36 +201,36 @@ fac(N) -> mult(X, Y) -> X * Y.</code> - <p>Note that we have also had to expand the <c>-export</c> line + <p>Notice that it is also required 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> + <p>Try out the new function <c>mult</c>:</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 + <p>In this example the numbers are integers and the arguments + in the functions in the code <c>N</c>, <c>X</c>, and <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 variables could be - <c>Number</c>, <c>ShoeSize</c>, <c>Age</c> etc.</p> + (see + <seealso marker="doc/reference_manual:expressions">Variables</seealso>). + Examples of variables are + <c>Number</c>, <c>ShoeSize</c>, and <c>Age</c>.</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> + <p>Atom is another data type in Erlang. Atoms start with a small + letter (see + <seealso marker="doc/reference_manual:data_types">Atom</seealso>), + for example, <c>charles</c>, + <c>centimeter</c>, and <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 in a file named <c>tut2.erl</c>). It can be + useful for converting from inches to centimeters and conversely:</p> <code type="none"> -module(tut2). -export([convert/2]). @@ -231,27 +240,30 @@ convert(M, inch) -> convert(N, centimeter) -> N * 2.54.</code> - <p>Compile and test:</p> + <p>Compile:</p> <pre> 9> <input>c(tut2).</input> {ok,tut2} +</pre> + <p>Test:</p> + <pre> 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> + <p>Notice the introduction of decimals (floating point numbers) + without any explanation. Hopefully you can cope with that.</p> + <p>Let us see what happens if something other than <c>centimeter</c> or + <c>inch</c> is entered in the <c>convert</c> function:</p> <pre> 12> <input>tut2:convert(3, miles).</input> ** exception error: no function clause matching tut2:convert(3,miles) (tut2.erl, line 4)</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 + clauses. As shown, <c>miles</c> is not part of either of + the clauses. The Erlang system cannot <em>match</em> either of + the clauses so an error message <c>function_clause</c> is returned. + 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> @@ -271,14 +283,15 @@ convert(N, centimeter) -> 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> + <p>Does this mean that 3 is in inches? Or does it mean that 3 is + in centimeters + and is to be converted to inches? Erlang has a way to group + things together to make things more understandable. These are called + <em>tuples</em> and are surrounded by curly brackets, "{" and "}".</p> + <p>So, <c>{inch,3}</c> denotes 3 inches and + <c>{centimeter,5}</c> denotes 5 centimeters. Now let us write a + new program that converts centimeters to inches and conversely. + Enter the following code in a file called <c>tut3.erl</c>):</p> <code type="none"> -module(tut3). -export([convert_length/1]). @@ -295,47 +308,48 @@ convert_length({inch, Y}) -> {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 + <p>Notice on line 16 that 5 inches is converted to centimeters and back + again and reassuringly get back to the original value. That is, 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 + Consider how line 16 (above) works. + The argument given to the function <c>{inch,5}</c> is first + matched against the first head clause of <c>convert_length</c>, + that is, <c>convert_length({centimeter,X})</c>. It can be seen that <c>{centimeter,X}</c> does not match <c>{inch,5}</c> - (the head is the bit before the "->"). 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 + (the head is the bit before the "->"). This having failed, + let us try + the head of the next clause that is, <c>convert_length({inch,Y})</c>. + This matches, and <c>Y</c> gets the value 5.</p> + <p>Tuples can have more than two parts, in fact + as many parts as you 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> + various cities of the world:</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> + <p>Tuples have a fixed number of items in them. Each item in a + tuple is called an <em>element</em>. In the tuple + <c>{moscow,{c,-10}}</c>, element 1 is <c>moscow</c> and element + 2 is <c>{c,-10}</c>. Here <c>c</c> represents Celsius and + <c>f</c> 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> + <p>Whereas tuples group things together, it is also needed to + represent lists of things. Lists in Erlang are surrounded by + square brackets, "[" and "]". For example, a list of the + temperatures of various cities in the world can 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> + <p>Notice that this list was so long that it did not fit on one line. + This does not matter, Erlang allows line breaks at all "sensible + places" but not, for example, in the middle of atoms, integers, + and others.</p> + <p>A 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] @@ -343,9 +357,9 @@ convert_length({inch, Y}) -> 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>To separate the first elements of the list from the rest of the + list, <c>|</c> is used. <c>First</c> has got value 1 and + <c>TheRest</c> has got the value [2,3,4,5].</p> <p>Another example:</p> <pre> 20> <input>[E1, E2 | R] = [1,2,3,4,5,6,7].</input> @@ -356,10 +370,10 @@ convert_length({inch, Y}) -> 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> + <p>Here you see the use of <c>|</c> to get the first two elements from + the list. If you try to get more elements from the list + than there are elements in the list, an error is returned. Notice + also the special case of the list with no elements, []:</p> <pre> 24> <input>[A, B | C] = [1, 2].</input> [1,2] @@ -369,13 +383,13 @@ convert_length({inch, Y}) -> 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 + <p>In the previous examples, new variable names are used, instead of + 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>, and <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> + context (scope). More about this later.</p> + <p>The following example shows how to find the length of a list. + Enter the following code in a file named <c>tut4.erl</c>):</p> <code type="none"> -module(tut4). @@ -385,7 +399,7 @@ list_length([]) -> 0; list_length([First | Rest]) -> 1 + list_length(Rest).</code> - <p>Compile (file <c>tut4.erl</c>) and test:</p> + <p>Compile and test:</p> <pre> 28> <input>c(tut4).</input> {ok,tut4} @@ -404,14 +418,14 @@ list_length([First | Rest]) -> <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 data 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 + <p>In general, tuples are used where "records" + or "structs" are used in other languages. Also, lists are used when + representing things with varying sizes, that is, where + linked lists are used in other languages.</p> + <p>Erlang does not have a string data type. Instead, strings can be + represented by lists of Unicode characters. This implies for example that + the list <c>[97,98,99]</c> is equivalent to "abc". The Erlang shell is + "clever" and guesses what list you mean and outputs it in what it thinks is the most appropriate form, for example:</p> <pre> 30> <input>[97,98,99].</input> @@ -420,16 +434,17 @@ list_length([First | Rest]) -> <section> <title>Maps</title> - <p>Maps are a set of key to value associations. These associations - are encapsulated with "#{" and "}". To create an association from - "key" to value 42, we write:</p> + <p>Maps are a set of key to value associations. These associations + are encapsulated with "#{" and "}". To create an association + from "key" to value 42:</p> <code type="none"> > #{ "key" => 42 }. #{"key" => 42}</code> - <p>We will jump straight into the deep end with an example using some - interesting features.</p> - <p>The following example shows how we calculate alpha blending using - maps to reference color and alpha channels:</p> + <p>Let us jump straight into the deep end with an example using some + interesting features.</p> + <p>The following example shows how to calculate alpha blending + using maps to reference color and alpha channels. Enter the code + in a file named <c>color.erl</c>):</p> <code type="none"> -module(color). @@ -468,7 +483,7 @@ green(#{green := SV, alpha := SA}, #{green := DV, alpha := DA}) -> SV*SA + DV*DA*(1.0 - SA). blue(#{blue := SV, alpha := SA}, #{blue := DV, alpha := DA}) -> SV*SA + DV*DA*(1.0 - SA).</code> - <p>Compile (file <c>color.erl</c>) and test:</p> + <p>Compile and test:</p> <pre> > <input>c(color).</input> {ok,color} @@ -484,50 +499,48 @@ blue(#{blue := SV, alpha := SA}, #{blue := DV, alpha := DA}) -> <p>This example warrants some explanation:</p> <code type="none"> -define(is_channel(V), (is_float(V) andalso V >= 0.0 andalso V =< 1.0)).</code> - <p> - First we define a macro <c>is_channel</c> to help with our guard tests. - This is only here for convenience and to reduce syntax cluttering. - - You can read more about <seealso marker="doc/reference_manual:macros">Macros</seealso> - in the Erlang Reference Manual. - </p> + <p>First a macro <c>is_channel</c> is defined to help with the + guard tests. This is only here for convenience and to reduce + syntax cluttering. For more information about macros, see + <seealso marker="doc/reference_manual:macros"> + The Preprocessor</seealso>. + </p> <code type="none"> new(R,G,B,A) when ?is_channel(R), ?is_channel(G), ?is_channel(B), ?is_channel(A) -> #{red => R, green => G, blue => B, alpha => A}.</code> - <p> - The function <c>new/4</c> creates a new map term with and lets the keys - <c>red</c>, <c>green</c>, <c>blue</c> and <c>alpha</c> be associated - with an initial value. In this case we only allow for float - values between and including 0.0 and 1.0 as ensured by the <c>?is_channel/1</c> macro - for each argument. Only the <c>=></c> operator is allowed when creating a new map. + <p>The function <c>new/4</c> creates a new map term and lets the keys + <c>red</c>, <c>green</c>, <c>blue</c>, and <c>alpha</c> be + associated with an initial value. In this case, only float + values between and including 0.0 and 1.0 are allowed, as ensured + by the <c>?is_channel/1</c> macro for each argument. Only the + <c>=></c> operator is allowed when creating a new map. + </p> + <p>By calling <c>blend/2</c> on any color term created by + <c>new/4</c>, the resulting color can be calculated as + determined by the two map terms. + </p> + <p>The first thing <c>blend/2</c> does is to calculate the + resulting alpha channel: </p> - <p> - By calling <c>blend/2</c> on any color term created by <c>new/4</c> we can calculate - the resulting color as determined by the two maps terms. - </p> - <p> - The first thing <c>blend/2</c> does is to calculate the resulting alpha channel. - </p> <code type="none"> alpha(#{alpha := SA}, #{alpha := DA}) -> SA + DA*(1.0 - SA).</code> - <p> - We fetch the value associated with key <c>alpha</c> for both arguments using - the <c>:=</c> operator. Any other keys - in the map are ignored, only the key <c>alpha</c> is required and checked for. - </p> - <p>This is also the case for functions <c>red/2</c>, <c>blue/2</c> and <c>green/2</c>.</p> + <p>The value associated with key <c>alpha</c> is fetched for both + arguments using the <c>:=</c> operator. The other keys in the + map are ignored, only the key <c>alpha</c> is required and + checked for. + </p> + <p>This is also the case for functions <c>red/2</c>, + <c>blue/2</c>, and <c>green/2</c>.</p> <code type="none"> red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) -> SV*SA + DV*DA*(1.0 - SA).</code> - <p> - The difference here is that we check for two keys in each map argument. The other keys - are ignored. - </p> - <p> - Finally we return the resulting color in <c>blend/3</c>. - </p> + <p>The difference here is that a check is made for two keys in + each map argument. The other keys are ignored. + </p> + <p>Finally, let us return the resulting color in <c>blend/3</c>: + </p> <code type="none"> blend(Src,Dst,Alpha) when Alpha > 0.0 -> Dst#{ @@ -536,20 +549,20 @@ blend(Src,Dst,Alpha) when Alpha > 0.0 -> blue := blue(Src,Dst) / Alpha, alpha := Alpha };</code> - <p> - We update the <c>Dst</c> map with new channel values. The syntax for updating an existing key with a new value is done with <c>:=</c> operator. - </p> + <p>The <c>Dst</c> map is updated with new channel values. The + syntax for updating an existing key with a new value is with the + <c>:=</c> operator. + </p> </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> + <p>Erlang has many standard modules to help you do things. For + example, the module <c>io</c> contains many functions that help + in doing 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 (the same place as you started + <c>erl</c>). Try the operating system shell command:</p> <pre> % <input>erl -man io</input> ERLANG MODULE DEFINITION io(3) @@ -561,21 +574,21 @@ 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 + <p>If this does not work on your system, the documentation is + included as HTML in the Erlang/OTP release. You can also 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> + (open source). For example, for Erlang/OTP 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 + <p>It is nice to be able to do formatted output in examples, so the next example shows a simple way 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> + function. 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 @@ -589,28 +602,28 @@ 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 + <p>The function <c>format/2</c> (that is, <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, + written between " ". This list is printed out as it is, 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 + handle errors which are shown later. As an exercise, try to + make <c>io:format</c> crash, it should not 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> + <p>Now for a larger example to consolidate what you have learnt so + far. Assume that you have a list of temperature readings from a number + of cities in the world. Some of them are in Celsius + and some in Fahrenheit (as in the previous list). First let us + convert them all to Celsius, then let us print the data neatly.</p> <code type="none"> %% This module is in file tut5.erl @@ -642,50 +655,50 @@ 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 + <p>Before looking at how this program works, notice that + a few comments are added to the code. A comment starts with a + %-character and goes on to the end of the line. Notice also 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 function <c>format_temps/1</c>. The other functions are + <em>local</em> functions, that is, 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> + <p>Notice also that when testing the program from the shell, + the input is spread over two lines as the line was too long.</p> + <p>When <c>format_temps</c> is called 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 + the rest of the list. So the function + <c>print_temp(convert_to_celsius({moscow,{c,-10}}))</c> is called.</p> + <p>Here is 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> + the function <c>print_temp</c>. When function calls are <em>nested</em> + like this, they execute (evaluate) from the inside out. + That is, first <c>convert_to_celsius({moscow,{c,-10}})</c> is evaluated, 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 + is already in Celsius. Then <c>print_temp({moscow,{c,-10}})</c> + is evaluated. + 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 + to what has been described above. Notice 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 + (see the <seealso marker="stdlib:io#fwrite/1">io(3)</seealso>) manual page in STDLIB.</p> + <p>Now <c>format_temps(Rest)</c> is called 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 + constructs in other languages. (Yes, this is recursion, but do not 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. [], + <c>{cape_town,{f,70}}</c> and the same procedure is repeated as + before. This is done until the list becomes empty, that is [], 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 + <title>Matching, Guards, and Scope of Variables</title> + <p>It can 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 + let us look at functions for finding the maximum value of the elements in a list:</p> <code type="none"> -module(tut6). @@ -705,53 +718,57 @@ list_max([Head|Rest], Result_so_far) -> {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 + <p>First notice that two functions have 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 + completely different functions. Where you need to distinguish + between these functions, you write Name/Arity, where + Name is the function name and Arity 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>. + <p>In this example you walk through a list "carrying" a + value, 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 + 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 you 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 + with something that is not a list at all, you would cause an error. + Notice 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> + <p>In <c>list_max/2</c>, you walk down the list and use <c>Head</c> instead of <c>Result_so_far</c> when <c>Head</c> > - <c>Result_so_far</c>. <c>when</c> is a special word we use before - the -> 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, < less than, > - greater than, == equal, >= greater or equal, =< 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 + <c>Result_so_far</c>. <c>when</c> is a special word used before + the -> in the function to say that you only use this part + of the function if the test that follows is true. A test + of this type is called <em>guard</em>. If the guard is false (that is, + the guard fails), the next part of the function is tried. In this + case, if <c>Head</c> is not greater than <c>Result_so_far</c>, then + it must be smaller or equal to it. This means that a guard on + the next part of the function is not needed.</p> + <p>Some useful operators in guards are: + </p><list type="bulleted"><item>< less than</item> + <item>> greater than</item> + <item>== equal</item> + <item>>= greater or equal</item> + <item>=< less or equal</item> + <item>/= not equal</item></list> + <p>(see <seealso marker="doc/reference_manual:expressions">Guard Sequences</seealso>).</p> + <p>To change the above program to one that works out the minimum + value of the element in a list, you only need to write < instead of >. (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 + the name of the function to <c>list_min</c>.)</p> + <p>Earlier it was mentioned that a variable can only be + given a value once in its scope. In the above you see + that <c>Result_so_far</c> is given several values. This is + OK since every time you call <c>list_max/2</c> you create a new + scope and one can regard <c>Result_so_far</c> as a 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 + the match operator = . So if you write <c>M = 5</c>, a variable + called <c>M</c> is created with the value 5. If, in + the same scope, you then write <c>M = 6</c>, an error is returned. Try this out in the shell:</p> <pre> 39> <input>M = 5.</input> @@ -771,21 +788,21 @@ list_max([Head|Rest], Result_so_far) -> paris 45> <input>Y.</input> {f,28}</pre> - <p>Here we see that <c>X</c> gets the value <c>paris</c> and + <p>Here <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> + <p>If you try to do the same again with another city, + an error is returned:</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> + programs. For example, in function <c>list_max/2</c> above, + you can 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> + <p>This is possibly a little clearer.</p> </section> <section> @@ -824,9 +841,9 @@ reverse([], Reversed_List) -> {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 + <p>Consider how <c>Reversed_List</c> is built. It starts as [], + then successively the heads are taken off of the list to be reversed + and added to the the <c>Reversed_List</c>, as shown in the following:</p> <code type="none"> reverse([1|2,3], []) => @@ -840,14 +857,15 @@ 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 let's 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> + <p>The module <c>lists</c> contains many functions for + manipulating lists, for example, for reversing them. So before + writing a list-manipulating function it is a good idea to check + if one not already is written for you + (see the <seealso marker="stdlib:lists">lists(3)</seealso> + manual page in STDLIB).</p> + <p>Now let us get back to the cities and temperatures, but take a more + structured approach this time. First let us convert the whole list + to Celsius as follows:</p> <code type="none"> -module(tut7). -export([format_temps/1]). @@ -864,6 +882,7 @@ convert_list_to_c([City | Rest]) -> convert_list_to_c([]) -> [].</code> + <p>Test the function:</p> <pre> 54> <input>c(tut7).</input> {ok, tut7}. @@ -874,26 +893,26 @@ convert_list_to_c([]) -> {stockholm,{c,-4}}, {paris,{c,-2.2222222222222223}}, {london,{c,2.2222222222222223}}]</pre> - <p>Looking at this bit by bit:</p> + <p>Explanation:</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 + <p>Here <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> + <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> + <p>This is done until the end of the list is reached, that is, + 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> + <p>Now when the list is converted, a function to print it is added:</p> <code type="none"> -module(tut7). -export([format_temps/1]). @@ -928,12 +947,12 @@ 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 + <p>Now a function has to be added to find the cities with + the maximum and minimum temperatures. The following program is not + the most efficient way of doing this as you 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> + needed.</p> <code type="none"><![CDATA[ -module(tut7). -export([format_temps/1]). @@ -1003,8 +1022,8 @@ ok</pre> <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> + minimum temperature. A new construct, <c>if</c>, is introduced here. + If works as follows:</p> <code type="none"> if Condition 1 -> @@ -1016,14 +1035,15 @@ if 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 + <p>Notice that there is no ";" before <c>end</c>. Conditions do + the same as guards, that is, tests that succeed or fail. Erlang + starts at the top + and tests until it finds a condition that succeeds. 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 + other conditions and actions before the <c>end</c>. If no + condition matches, a run-time failure occurs. A condition + that always succeeds is the atom <c>true</c>. 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> @@ -1039,10 +1059,10 @@ test_if(A, B) -> B == 6 -> io:format("B == 6~n", []), b_equals_6; - A == 2, B == 3 -> %i.e. A equals 2 and B equals 3 + A == 2, B == 3 -> %That is 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 + A == 1 ; B == 7 -> %That is A equals 1 or B equals 7 io:format("A == 1 ; B == 7~n", []), a_equals_1_or_b_equals_7 end.</code> @@ -1068,19 +1088,19 @@ 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 (tut9.erl, line 5)</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> + <p>Notice that <c>tut9:test_if(33,33)</c> does not cause any + condition to succeed. This leads to the run time error + <c>if_clause</c>, here nicely formatted by the shell. See + <seealso marker="doc/reference_manual:expressions">Guard Sequences</seealso> + for details of the many guard tests available.</p> + <p><c>case</c> is another construct in Erlang. Recall that the + <c>convert_length</c> function was written 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> + <p>The same program can also be written as:</p> <code type="none"> -module(tut10). -export([convert_length/1]). @@ -1099,12 +1119,13 @@ convert_length(Length) -> {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 + <p>Both <c>case</c> and <c>if</c> have <em>return values</em>, that is, + 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> + The following example clarifies this. It + tells us the length of a month, given the year. + The year must be known, since February has 29 days in a leap year.</p> <code type="none"> -module(tut11). -export([month_length/2]). @@ -1150,57 +1171,58 @@ month_length(Year, Month) -> </section> <section> - <title>Built In Functions (BIFs)</title> - <p>Built in functions (BIFs) are functions which for some reason are - built in to the Erlang virtual machine. BIFs often implement - functionality that is impossible to implement in Erlang or is too - inefficient to implement in Erlang. Some BIFs can be called - by use of the function name only, but they by default belong - to the erlang module. So for example, the call to the BIF <c>trunc</c> + <title>Built-In Functions (BIFs)</title> + <p>BIFs are functions that for some reason are + built-in to the Erlang virtual machine. BIFs often implement + functionality that is impossible or is too + inefficient to implement in Erlang. Some BIFs can be called + using the function name only but they are by default belonging + to the <c>erlang</c> module. For example, the call to the + BIF <c>trunc</c> below is equivalent to 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> + <p>As shown, first it is checked if a year is leap. If a + year is divisible by 400, it is a leap year. To determine this, + first divide the year by 400 and use the BIF + <c>trunc</c> (more about this later) to cut off any decimals. Then + multiply by 400 again and see if the same value is returned again. + 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> + <p>2000 is not the same as 2004, so 2004 is not 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, which check 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 ends 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 + <p>That is, a leap year. The next two <c>trunc</c>-tests evaluate + if the year is divisible by 100 or 4 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>. This variable is used in the guard + for <c>feb</c> in the following <c>case</c> that 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> + <p>This example showed the use of <c>trunc</c>. It is easier + to use the Erlang operator <c>rem</c> that gives the remainder + after division, for example:</p> <pre> 74> <input>2004 rem 400.</input> 4</pre> - <p>so instead of writing:</p> + <p>So instead of writing:</p> <code type="none"> trunc(Year / 400) * 400 == Year -> leap;</code> - <p>we could write:</p> + <p>it can be written:</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, + <p>There are many other BIFs such as + <c>trunc</c>. Only a few BIFs 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> + (see + <seealso marker="doc/reference_manual:expressions">Guard Sequences</seealso>) + (For advanced readers: This is to ensure that guards do not have side + effects.) Let us play with a few of these functions in the shell:</p> <pre> 75> <input>trunc(5.6).</input> 5 @@ -1218,7 +1240,7 @@ false 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 + <p>All of these can be used in guards. Now for some BIFs that cannot be used in guards:</p> <pre> 83> <input>atom_to_list(hello).</input> @@ -1227,22 +1249,22 @@ false</pre> goodbye 85> <input>integer_to_list(22).</input> "22"</pre> - <p>The 3 BIFs above do conversions which would be difficult (or + <p>These three BIFs do conversions that would be difficult (or impossible) to do in Erlang.</p> </section> <section> - <title>Higher Order Functions (Funs)</title> + <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> + higher-order functions. Here is an example using the shell:</p> <pre> 86> <input>Xf = fun(X) -> X * 2 end.</input> #Fun<erl_eval.5.123085357> 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 + <p>Here is defined a function that doubles + the value of a number and assigned this function to a variable. Thus + <c>Xf(5)</c> returns 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"> @@ -1258,17 +1280,16 @@ 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 + 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 + the shell, <c>map</c> is used 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<erl_eval.5.123085357> 89> <input>lists:map(Add_3, [1,2,3]).</input> [4,5,6]</pre> - <p>Now let's print out the temperatures in a list of cities (yet - again):</p> + <p>Let us (again) print the temperatures in a list of cities:</p> <pre> 90> <input>Print_City = fun({City, {X, Temp}}) -> io:format("~-15w ~w ~w~n",</input> <input>[City, X, Temp]) end.</input> @@ -1281,7 +1302,7 @@ 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 + <p>Let us now define a fun that can be used to go through a list of cities and temperatures and transform them all to Celsius.</p> <code type="none"> -module(tut13). @@ -1303,21 +1324,21 @@ convert_list_to_c(List) -> {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> + <p>The <c>convert_to_c</c> function is the same as before, but here + it is used 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 + <p>When a function defined elsewhere is used as a fun, it can be referred + to as <c>Function/Arity</c> (remember that <c>Arity</c> = + number of arguments). So in the <c>map</c>-call + <c>lists:map(fun convert_to_c/1, List)</c> is written. As shown, <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 + arguments. This fun returns <c>true</c> if 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> + Sorting is added to the <c>convert_list_to_c</c>:</p> <code type="none"><![CDATA[ -module(tut13). @@ -1342,13 +1363,13 @@ convert_list_to_c(List) -> {paris,{c,-2}}, {london,{c,2}}, {cape_town,{c,21}}]</pre> - <p>In <c>sort</c> we use the fun:</p> + <p>In <c>sort</c> the fun is used:</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> + <p>Here the concept of an <em>anonymous variable</em> + "_" is introduced. This is simply shorthand for a variable that + gets a value, but the value is ignored. This can be used + anywhere suitable, not just in funs. <c><![CDATA[Temp1 < Temp2]]></c> returns <c>true</c> if <c>Temp1</c> is less than <c>Temp2</c>.</p> </section> </chapter> |