diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /system/doc/getting_started/seq_prog.xml | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'system/doc/getting_started/seq_prog.xml')
-rw-r--r-- | system/doc/getting_started/seq_prog.xml | 1231 |
1 files changed, 1231 insertions, 0 deletions
diff --git a/system/doc/getting_started/seq_prog.xml b/system/doc/getting_started/seq_prog.xml new file mode 100644 index 0000000000..bc1758d855 --- /dev/null +++ b/system/doc/getting_started/seq_prog.xml @@ -0,0 +1,1231 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Sequential Programming</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>seq_prog.xml</file> + </header> + + <section> + <title>The Erlang Shell</title> + <p>Most operating systems have a command interpreter or shell, Unix + and Linux have many, Windows has the Command Prompt. Erlang has + its own shell where you can directly write bits of Erlang code + and evaluate (run) them to see what happens (see + <seealso marker="stdlib:shell">shell(3)</seealso>). Start + the Erlang shell (in Linux or UNIX) by starting a shell or + command interpreter in your operating system and typing + <c>erl</c>, you will see something like this.</p> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2 [source] [hipe] + +Eshell V5.2 (abort with ^G) +1></pre> + <p>Now type in "2 + 5." as shown below.</p> + <pre> +1> <input>2 + 5.</input> +7 +2></pre> + <p>In Windows, the shell is started by double-clicking on the Erlang + shell icon.</p> + <p>You'll notice that the Erlang shell has numbered the lines that + can be entered, (as 1> 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> + <pre> +2> <input>(42 + 77) * 66 / 3.</input> +2618.0</pre> + <p>Here you can see the use of brackets and the multiplication + operator "*" and division operator "/", just as in normal + arithmetic (see the chapter + <seealso marker="doc/reference_manual:expressions">"Arithmetic Expressions"</seealso> in the Erlang Reference Manual).</p> + <p>To shutdown the Erlang system and the Erlang shell type + Control-C. You will see the following output:</p> + <pre> +BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded + (v)ersion (k)ill (D)b-tables (d)istribution +<input>a</input> +%</pre> + <p>Type "a" to leave the Erlang system.</p> + <p>Another way to shutdown the Erlang system is by entering + <c>halt()</c>:</p> + <pre> +3> <input>halt().</input> +% </pre> + </section> + + <section> + <title>Modules and Functions</title> + <p>A programming language isn't much use if you can just run code + from the shell. So here is a small Erlang program. Enter it into + a file called <c>tut.erl</c> (the file name <c>tut.erl</c> is + important, also make sure that it is in the same directory as + the one where you started <c>erl</c>) using a suitable + text editor. If you are lucky your editor will have an Erlang + mode which will make it easier for you to enter and format your + code nicely (see the chapter + <seealso marker="tools:erlang_mode_chapter">"The Erlang mode for Emacs"</seealso> in Tools User's Guide), but you can manage + perfectly well without. Here's the code to enter:</p> + <code type="none"> +-module(tut). +-export([double/1]). + +double(X) -> + 2 * X.</code> + <p>It's not hard to guess that this "program" doubles the value of + numbers. I'll get back to the first two lines later. Let's compile + the program. This can be done in your Erlang shell as shown below:</p> + <pre> +3> <input>c(tut).</input> +{ok,tut}</pre> + <p>The <c>{ok,tut}</c> tells you that the compilation was OK. If it + said "error" instead, you have made some mistake in the text you + entered and there will also be error messages to give you some + idea as to what has gone wrong so you can change what you have + written and try again.</p> + <p>Now lets run the program.</p> + <pre> +4> <input>tut:double(10).</input> +20</pre> + <p>As expected double of 10 is 20.</p> + <p>Now let's get back to the first two lines. Erlang programs are + written in files. Each file contains what we call an Erlang + <em>module</em>. The first line of code in the module tells us + the name of the module (see the chapter + <seealso marker="doc/reference_manual:modules">"Modules"</seealso> + in the Erlang Reference Manual).</p> + <code type="none"> +-module(tut).</code> + <p>This tells us that the module is called <em>tut</em>. Note + the "." at the end of the line. The files which are used to store + the module must have the same name as the module but with + the extension ".erl". In our case the file name is <c>tut.erl</c>. + When we use a function in another module, we use the syntax, + <c>module_name:function_name(arguments)</c>. So</p> + <pre> +4> <input>tut:double(10).</input></pre> + <p>means call function <c>double</c> in module <c>tut</c> with + argument "10".</p> + <p>The second line:</p> + <code type="none"> +-export([double/1]).</code> + <p>says that the module <c>tut</c> contains a function called + <c>double</c> which takes one argument (<c>X</c> in our example) + and that this function can be called from outside the module + <c>tut</c>. More about this later. Again note the "." at the end + of the line.</p> + <p>Now for a more complicated example, the factorial of a number + (e.g. factorial of 4 is 4 * 3 * 2 * 1). Enter the following code + in a file called <c>tut1.erl</c>.</p> + <code type="none"> +-module(tut1). +-export([fac/1]). + +fac(1) -> + 1; +fac(N) -> + N * fac(N - 1).</code> + <p>Compile the file</p> + <pre> +5> <input>c(tut1).</input> +{ok,tut1}</pre> + <p>And now calculate the factorial of 4.</p> + <pre> +6> <input>tut1:fac(4).</input> +24</pre> + <p>The first part:</p> + <code type="none"> +fac(1) -> + 1;</code> + <p>says that the factorial of 1 is 1. Note that we end this part + with a ";" which indicates that there is more of this function to + come. The second part:</p> + <code type="none"> +fac(N) -> + N * fac(N - 1).</code> + <p>says that the factorial of N is N multiplied by the factorial of + N - 1. Note that this part ends with a "." saying that there are + no more parts of this function.</p> + <p>A function can have many arguments. Let's expand the module + <c>tut1</c> with the rather stupid function to multiply two + numbers:</p> + <code type="none"> +-module(tut1). +-export([fac/1, mult/2]). + +fac(1) -> + 1; +fac(N) -> + N * fac(N - 1). + +mult(X, Y) -> + X * Y.</code> + <p>Note that we have also had to expand the <c>-export</c> line + with the information that there is another function <c>mult</c> + with two arguments.</p> + <p>Compile:</p> + <pre> +7> <input>c(tut1).</input> +{ok,tut1}</pre> + <p>and try it out:</p> + <pre> +8> <input>tut1:mult(3,4).</input> +12</pre> + <p>In the example above the numbers are integers and the arguments + in the functions in the code, <c>N</c>, <c>X</c>, <c>Y</c> are + called variables. Variables must start with a capital letter + (see the chapter + <seealso marker="doc/reference_manual:expressions">"Variables"</seealso> + in the Erlang Reference Manual). Examples of variable could be + <c>Number</c>, <c>ShoeSize</c>, <c>Age</c> etc.</p> + </section> + + <section> + <title>Atoms</title> + <p>Atoms are another data type in Erlang. Atoms start with a small + letter ((see the chapter + <seealso marker="doc/reference_manual:data_types">"Atom"</seealso> + in the Erlang Reference Manual)), for example: <c>charles</c>, + <c>centimeter</c>, <c>inch</c>. Atoms are simply names, nothing + else. They are not like variables which can have a value.</p> + <p>Enter the next program (file: <c>tut2.erl</c>) which could be + useful for converting from inches to centimeters and vice versa:</p> + <code type="none"> +-module(tut2). +-export([convert/2]). + +convert(M, inch) -> + M / 2.54; + +convert(N, centimeter) -> + N * 2.54.</code> + <p>Compile and test:</p> + <pre> +9> <input>c(tut2).</input> +{ok,tut2} +10> <input>tut2:convert(3, inch).</input> +1.1811023622047243 +11> <input>tut2:convert(7, centimeter).</input> +17.78</pre> + <p>Notice that I have introduced decimals (floating point numbers) + without any explanation, but I guess you can cope with that.</p> + <p>See what happens if I enter something other than centimeter or + inch in the convert function:</p> + <pre> +12> <input>tut2:convert(3, miles).</input> +** exception error: no function clause matching tut2:convert(3,miles)</pre> + <p>The two parts of the <c>convert</c> function are called its + clauses. Here we see that "miles" is not part of either of + the clauses. The Erlang system can't <em>match</em> either of + the clauses so we get an error message <c>function_clause</c>. + The shell formats the error message nicely, but the error tuple + is saved in the shell's history list and can be output by the shell + command <c>v/1</c>:</p> + <pre> +13> <input>v(12).</input> +{'EXIT',{function_clause,[{tut2,convert,[3,miles]}, + {erl_eval,do_apply,5}, + {shell,exprs,6}, + {shell,eval_exprs,6}, + {shell,eval_loop,3}]}}</pre> + + </section> + + <section> + <title>Tuples</title> + <p>Now the <c>tut2</c> program is hardly good programming style. + Consider:</p> + <code type="none"> +tut2:convert(3, inch).</code> + <p>Does this mean that 3 is in inches? or that 3 is in centimeters + and we want to convert it to inches? So Erlang has a way to group + things together to make things more understandable. We call these + <em>tuples</em>. Tuples are surrounded by "{" and "}".</p> + <p>So we can write <c>{inch,3}</c> to denote 3 inches and + <c>{centimeter,5}</c> to denote 5 centimeters. Now let's write a + new program which converts centimeters to inches and vice versa. + (file <c>tut3.erl</c>).</p> + <code type="none"> +-module(tut3). +-export([convert_length/1]). + +convert_length({centimeter, X}) -> + {inch, X / 2.54}; +convert_length({inch, Y}) -> + {centimeter, Y * 2.54}.</code> + <p>Compile and test:</p> + <pre> +14> <input>c(tut3).</input> +{ok,tut3} +15> <input>tut3:convert_length({inch, 5}).</input> +{centimeter,12.7} +16> <input>tut3:convert_length(tut3:convert_length({inch, 5})).</input> +{inch,5.0}</pre> + <p>Note on line 16 we convert 5 inches to centimeters and back + again and reassuringly get back to the original value. I.e + the argument to a function can be the result of another function. + Pause for a moment and consider how line 16 (above) works. + The argument we have given the function <c>{inch,5}</c> is first + matched against the first head clause of <c>convert_length</c> + i.e. <c>convert_length({centimeter,X})</c> where it can be seen + that <c>{centimeter,X}</c> does not match <c>{inch,5}</c> + (the head is the bit before the "->"). This having failed, we try + the head of the next clause i.e. <c>convert_length({inch,Y})</c>, + this matches and <c>Y</c> get the value 5.</p> + <p>We have shown tuples with two parts above, but tuples can have + as many parts as we want and contain any valid Erlang + <em>term</em>. For example, to represent the temperature of + various cities of the world we could write</p> + <code type="none"> +{moscow, {c, -10}} +{cape_town, {f, 70}} +{paris, {f, 28}}</code> + <p>Tuples have a fixed number of things in them. We call each thing + in a tuple an element. So in the tuple <c>{moscow,{c,-10}}</c>, + element 1 is <c>moscow</c> and element 2 is <c>{c,-10}</c>. I + have chosen <c>c</c> meaning Centigrade (or Celsius) and <c>f</c> + meaning Fahrenheit.</p> + </section> + + <section> + <title>Lists</title> + <p>Whereas tuples group things together, we also want to be able to + represent lists of things. Lists in Erlang are surrounded by "[" + and "]". For example a list of the temperatures of various cities + in the world could be:</p> + <code type="none"> +[{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, + {paris, {f, 28}}, {london, {f, 36}}]</code> + <p>Note that this list was so long that it didn't fit on one line. + This doesn't matter, Erlang allows line breaks at all "sensible + places" but not, for example, in the middle of atoms, integers + etc.</p> + <p>A very useful way of looking at parts of lists, is by using "|". + This is best explained by an example using the shell.</p> + <pre> +17> <input>[First |TheRest] = [1,2,3,4,5].</input> +[1,2,3,4,5] +18> <input>First.</input> +1 +19> <input>TheRest.</input> +[2,3,4,5]</pre> + <p>We use | to separate the first elements of the list from + the rest of the list. (<c>First</c> has got value 1 and + <c>TheRest</c> value [2,3,4,5]).</p> + <p>Another example:</p> + <pre> +20> <input>[E1, E2 | R] = [1,2,3,4,5,6,7].</input> +[1,2,3,4,5,6,7] +21> <input>E1.</input> +1 +22> <input>E2.</input> +2 +23> <input>R.</input> +[3,4,5,6,7]</pre> + <p>Here we see the use of | to get the first two elements from + the list. Of course if we try to get more elements from the list + than there are elements in the list we will get an error. Note + also the special case of the list with no elements [].</p> + <pre> +24> <input>[A, B | C] = [1, 2].</input> +[1,2] +25> <input>A.</input> +1 +26> <input>B.</input> +2 +27> <input>C.</input> +[]</pre> + <p>In all the examples above, I have been using new variable names, + not reusing the old ones: <c>First</c>, <c>TheRest</c>, <c>E1</c>, + <c>E2</c>, <c>R</c>, <c>A</c>, <c>B</c>, <c>C</c>. The reason + for this is that a variable can only be given a value once in its + context (scope). I'll get back to this later, it isn't so + peculiar as it sounds!</p> + <p>The following example shows how we find the length of a list:</p> + <code type="none"> +-module(tut4). + +-export([list_length/1]). + +list_length([]) -> + 0; +list_length([First | Rest]) -> + 1 + list_length(Rest).</code> + <p>Compile (file <c>tut4.erl</c>) and test:</p> + <pre> +28> <input>c(tut4).</input> +{ok,tut4} +29> <input>tut4:list_length([1,2,3,4,5,6,7]).</input> +7</pre> + <p>Explanation:</p> + <code type="none"> +list_length([]) -> + 0;</code> + <p>The length of an empty list is obviously 0.</p> + <code type="none"> +list_length([First | Rest]) -> + 1 + list_length(Rest).</code> + <p>The length of a list with the first element <c>First</c> and + the remaining elements <c>Rest</c> is 1 + the length of + <c>Rest</c>.</p> + <p>(Advanced readers only: This is not tail recursive, there is a + better way to write this function).</p> + <p>In general we can say we use tuples where we would use "records" + or "structs" in other languages and we use lists when we want to + represent things which have varying sizes, (i.e. where we would + use linked lists in other languages).</p> + <p>Erlang does not have a string date type, instead strings can be + represented by lists of ASCII characters. So the list + <c>[97,98,99]</c> is equivalent to "abc". The Erlang shell is + "clever" and guesses the what sort of list we mean and outputs it + in what it thinks is the most appropriate form, for example:</p> + <pre> +30> <input>[97,98,99].</input> +"abc"</pre> + </section> + + <section> + <title>Standard Modules and Manual Pages</title> + <p>Erlang has a lot of standard modules to help you do things. For + example, the module <c>io</c> contains a lot of functions to help + you do formatted input/output. To look up information about + standard modules, the command <c>erl -man</c> can be used at + the operating shell or command prompt (i.e. at the same place as + that where you started <c>erl</c>). Try the operating system + shell command:</p> + <pre> +% <input>erl -man io</input> +ERLANG MODULE DEFINITION io(3) + +MODULE + io - Standard I/O Server Interface Functions + +DESCRIPTION + This module provides an interface to standard Erlang IO + servers. The output functions all return ok if they are suc- + ...</pre> + <p>If this doesn't work on your system, the documentation is + included as HTML in the Erlang/OTP release, or you can read + the documentation as HTML or download it as PDF from either of + the sites www.erlang.se (commercial Erlang) or www.erlang.org + (open source), for example for release R9B:</p> + <code type="none"> +http://www.erlang.org/doc/r9b/doc/index.html</code> + </section> + + <section> + <title>Writing Output to a Terminal</title> + <p>It's nice to be able to do formatted output in these example, so + the next example shows a simple way to use to use + the <c>io:format</c> function. Of course, just like all other + exported functions, you can test the <c>io:format</c> function in + the shell:</p> + <pre> +31> <input>io:format("hello world~n", []).</input> +hello world +ok +32> <input>io:format("this outputs one Erlang term: ~w~n", [hello]).</input> +this outputs one Erlang term: hello +ok +33> <input>io:format("this outputs two Erlang terms: ~w~w~n", [hello, world]).</input> +this outputs two Erlang terms: helloworld +ok +34> <input>io:format("this outputs two Erlang terms: ~w ~w~n", [hello, world]).</input> +this outputs two Erlang terms: hello world +ok</pre> + <p>The function <c>format/2</c> (i.e. <c>format</c> with two + arguments) takes two lists. The first one is nearly always a list + written between " ". This list is printed out as it stands, + except that each ~w is replaced by a term taken in order from + the second list. Each ~n is replaced by a new line. + The <c>io:format/2</c> function itself returns the atom <c>ok</c> + if everything goes as planned. Like other functions in Erlang, it + crashes if an error occurs. This is not a fault in Erlang, it is + a deliberate policy. Erlang has sophisticated mechanisms to + handle errors which we will show later. As an exercise, try to + make <c>io:format</c> crash, it shouldn't be difficult. But + notice that although <c>io:format</c> crashes, the Erlang shell + itself does not crash.</p> + </section> + + <section> + <title>A Larger Example</title> + <p>Now for a larger example to consolidate what we have learnt so + far. Assume we have a list of temperature readings from a number + of cities in the world. Some of them are in Celsius (Centigrade) + and some in Fahrenheit (as in the previous list). First let's + convert them all to Celsius, then let's print out the data neatly.</p> + <code type="none"> +%% This module is in file tut5.erl + +-module(tut5). +-export([format_temps/1]). + +%% Only this function is exported +format_temps([])-> % No output for an empty list + ok; +format_temps([City | Rest]) -> + print_temp(convert_to_celsius(City)), + format_temps(Rest). + +convert_to_celsius({Name, {c, Temp}}) -> % No conversion needed + {Name, {c, Temp}}; +convert_to_celsius({Name, {f, Temp}}) -> % Do the conversion + {Name, {c, (Temp - 32) * 5 / 9}}. + +print_temp({Name, {c, Temp}}) -> + io:format("~-15w ~w c~n", [Name, Temp]).</code> + <pre> +35> <input>c(tut5).</input> +{ok,tut5} +36> <input>tut5:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow -10 c +cape_town 21.11111111111111 c +stockholm -4 c +paris -2.2222222222222223 c +london 2.2222222222222223 c +ok</pre> + <p>Before we look at how this program works, notice that we have + added a few comments to the code. A comment starts with a % + character and goes on to the end of the line. Note as well that + the <c>-export([format_temps/1]).</c> line only includes + the function <c>format_temps/1</c>, the other functions are + <em>local</em> functions, i.e. they are not visible from outside + the module <c>tut5</c>.</p> + <p>Note as well that when testing the program from the shell, I had + to spread the input over two lines as the line was too long.</p> + <p>When we call <c>format_temps</c> the first time, <c>City</c> + gets the value <c>{moscow,{c,-10}}</c> and <c>Rest</c> is + the rest of the list. So we call the function + <c>print_temp(convert_to_celsius({moscow,{c,-10}}))</c>.</p> + <p>Here we see a function call as + <c>convert_to_celsius({moscow,{c,-10}})</c> as the argument to + the function <c>print_temp</c>. When we <em>nest</em> function + calls like this we execute (evaluate) them from the inside out. + I.e. we first evaluate <c>convert_to_celsius({moscow,{c,-10}})</c> + which gives the value <c>{moscow,{c,-10}}</c> as the temperature + is already in Celsius and then we evaluate + <c>print_temp({moscow,{c,-10}})</c>. The function + <c>convert_to_celsius</c> works in a similar way to + the <c>convert_length</c> function in the previous example.</p> + <p><c>print_temp</c> simply calls <c>io:format</c> in a similar way + to what has been described above. Note that ~-15w says to print + the "term" with a field length (width) of 15 and left justify it. + (<seealso marker="stdlib:io#fwrite/1">io(3)</seealso>).</p> + <p>Now we call <c>format_temps(Rest)</c> with the rest of the list + as an argument. This way of doing things is similar to the loop + constructs in other languages. (Yes, this is recursion, but don't + let that worry you). So the same <c>format_temps</c> function is + called again, this time <c>City</c> gets the value + <c>{cape_town,{f,70}}</c> and we repeat the same procedure as + before. We go on doing this until the list becomes empty, i.e. [], + which causes the first clause <c>format_temps([])</c> to match. + This simply returns (results in) the atom <c>ok</c>, so + the program ends.</p> + </section> + + <section> + <title>Matching, Guards and Scope of Variables</title> + <p>It could be useful to find the maximum and minimum temperature + in lists like this. Before extending the program to do this, + let's look at functions for finding the maximum value of + the elements in a list:</p> + <code type="none"> +-module(tut6). +-export([list_max/1]). + +list_max([Head|Rest]) -> + list_max(Rest, Head). + +list_max([], Res) -> + Res; +list_max([Head|Rest], Result_so_far) when Head > Result_so_far -> + list_max(Rest, Head); +list_max([Head|Rest], Result_so_far) -> + list_max(Rest, Result_so_far).</code> + <pre> +37> <input>c(tut6).</input> +{ok,tut6} +38> <input>tut6:list_max([1,2,3,4,5,7,4,3,2,1]).</input> +7</pre> + <p>First note that we have two functions here with the same name + <c>list_max</c>. However each of these takes a different number + of arguments (parameters). In Erlang these are regarded as + completely different functions. Where we need to distinguish + between these functions we write <c>name/arity</c>, where + <c>name</c> is the name of the function and <c>arity</c> is + the number of arguments, in this case <c>list_max/1</c> and + <c>list_max/2</c>.</p> + <p>This is an example where we walk through a list "carrying" a + value with us, in this case <c>Result_so_far</c>. + <c>list_max/1</c> simply assumes that the max value of the list + is the head of the list and calls <c>list_max/2</c> with the rest + of the list and the value of the head of the list, in the above + this would be <c>list_max([2,3,4,5,7,4,3,2,1],1)</c>. If we tried + to use <c>list_max/1</c> with an empty list or tried to use it + with something which isn't a list at all, we would cause an error. + Note that the Erlang philosophy is not to handle errors of this + type in the function they occur, but to do so elsewhere. More + about this later.</p> + <p>In <c>list_max/2</c> we walk down the list and use <c>Head</c> + instead of <c>Result_so_far</c> when <c>Head</c> > + <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 + 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 + different variable in each scope.</p> + <p>Another way of creating and giving a variable a value is by using + the match operator = . So if I write <c>M = 5</c>, a variable + called <c>M</c> will be created and given the value 5. If, in + the same scope I then write <c>M = 6</c>, I'll get an error. Try + this out in the shell:</p> + <pre> +39> <input>M = 5.</input> +5 +40> <input>M = 6.</input> +** exception error: no match of right hand side value 6 +41> <input>M = M + 1.</input> +** exception error: no match of right hand side value 6 +42> <input>N = M + 1.</input> +6</pre> + <p>The use of the match operator is particularly useful for pulling + apart Erlang terms and creating new ones.</p> + <pre> +43> <input>{X, Y} = {paris, {f, 28}}.</input> +{paris,{f,28}} +44> <input>X.</input> +paris +45> <input>Y.</input> +{f,28}</pre> + <p>Here we see that <c>X</c> gets the value <c>paris</c> and + <c>Y</c><c>{f,28}</c>.</p> + <p>Of course if we try to do the same again with another city, we + get an error:</p> + <pre> +46> <input>{X, Y} = {london, {f, 36}}.</input> +** exception error: no match of right hand side value {london,{f,36}}</pre> + <p>Variables can also be used to improve the readability of + programs, for example, in the <c>list_max/2</c> function above, + we could write:</p> + <code type="none"> +list_max([Head|Rest], Result_so_far) when Head > Result_so_far -> + New_result_far = Head, + list_max(Rest, New_result_far);</code> + <p>which is possibly a little clearer.</p> + </section> + + <section> + <title>More About Lists</title> + <p>Remember that the | operator can be used to get the head of a + list:</p> + <pre> +47> <input>[M1|T1] = [paris, london, rome].</input> +[paris,london,rome] +48> <input>M1.</input> +paris +49> <input>T1.</input> +[london,rome]</pre> + <p>The | operator can also be used to add a head to a list:</p> + <pre> +50> <input>L1 = [madrid | T1].</input> +[madrid,london,rome] +51> <input>L1.</input> +[madrid,london,rome]</pre> + <p>Now an example of this when working with lists - reversing + the order of a list:</p> + <code type="none"> +-module(tut8). + +-export([reverse/1]). + +reverse(List) -> + reverse(List, []). + +reverse([Head | Rest], Reversed_List) -> + reverse(Rest, [Head | Reversed_List]); +reverse([], Reversed_List) -> + Reversed_List.</code> + <pre> +52> <input>c(tut8).</input> +{ok,tut8} +53> <input>tut8:reverse([1,2,3]).</input> +[3,2,1]</pre> + <p>Consider how <c>Reversed_List</c> is built. It starts as [], we + then successively take off the heads of the list to be reversed + and add them to the the <c>Reversed_List</c>, as shown in + the following:</p> + <code type="none"> +reverse([1|2,3], []) => + reverse([2,3], [1|[]]) + +reverse([2|3], [1]) => + reverse([3], [2|[1]) + +reverse([3|[]], [2,1]) => + reverse([], [3|[2,1]]) + +reverse([], [3,2,1]) => + [3,2,1]</code> + <p>The module <c>lists</c> contains a lot of functions for + manipulating lists, for example for reversing them, so before you + write a list manipulating function it is a good idea to check + that one isn't already written for you. (see + <seealso marker="stdlib:lists">lists(3)</seealso>).</p> + <p>Now lets get back to the cities and temperatures, but take a more + structured approach this time. First let's convert the whole list + to Celsius as follows and test the function:</p> + <code type="none"> +-module(tut7). +-export([format_temps/1]). + +format_temps(List_of_cities) -> + convert_list_to_c(List_of_cities). + +convert_list_to_c([{Name, {f, F}} | Rest]) -> + Converted_City = {Name, {c, (F -32)* 5 / 9}}, + [Converted_City | convert_list_to_c(Rest)]; + +convert_list_to_c([City | Rest]) -> + [City | convert_list_to_c(Rest)]; + +convert_list_to_c([]) -> + [].</code> + <pre> +54> <input>c(tut7).</input> +{ok, tut7}. +55> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +[{moscow,{c,-10}}, + {cape_town,{c,21.11111111111111}}, + {stockholm,{c,-4}}, + {paris,{c,-2.2222222222222223}}, + {london,{c,2.2222222222222223}}]</pre> + <p>Looking at this bit by bit:</p> + <code type="none"> +format_temps(List_of_cities) -> + convert_list_to_c(List_of_cities).</code> + <p>Here we see that <c>format_temps/1</c> calls + <c>convert_list_to_c/1</c>. <c>convert_list_to_c/1</c> takes off + the head of the <c>List_of_cities</c>, converts it to Celsius if + needed. The | operator is used to add the (maybe) converted + to the converted rest of the list:</p> + <code type="none"> +[Converted_City | convert_list_to_c(Rest)];</code> + <p>or</p> + <code type="none"> +[City | convert_list_to_c(Rest)];</code> + <p>We go on doing this until we get to the end of the list (i.e. + the list is empty:</p> + <code type="none"> +convert_list_to_c([]) -> + [].</code> + <p>Now we have converted the list, we add a function to print it:</p> + <code type="none"> +-module(tut7). +-export([format_temps/1]). + +format_temps(List_of_cities) -> + Converted_List = convert_list_to_c(List_of_cities), + print_temp(Converted_List). + +convert_list_to_c([{Name, {f, F}} | Rest]) -> + Converted_City = {Name, {c, (F -32)* 5 / 9}}, + [Converted_City | convert_list_to_c(Rest)]; + +convert_list_to_c([City | Rest]) -> + [City | convert_list_to_c(Rest)]; + +convert_list_to_c([]) -> + []. + +print_temp([{Name, {c, Temp}} | Rest]) -> + io:format("~-15w ~w c~n", [Name, Temp]), + print_temp(Rest); +print_temp([]) -> + ok.</code> + <pre> +56> <input>c(tut7).</input> +{ok,tut7} +57> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow -10 c +cape_town 21.11111111111111 c +stockholm -4 c +paris -2.2222222222222223 c +london 2.2222222222222223 c +ok</pre> + <p>We now have to add a function to find the cities with + the maximum and minimum temperatures. The program below isn't + the most efficient way of doing this as we walk through the list + of cities four times. But it is better to first strive for + clarity and correctness and to make programs efficient only if + really needed.</p> + <code type="none"><![CDATA[ +-module(tut7). +-export([format_temps/1]). + +format_temps(List_of_cities) -> + Converted_List = convert_list_to_c(List_of_cities), + print_temp(Converted_List), + {Max_city, Min_city} = find_max_and_min(Converted_List), + print_max_and_min(Max_city, Min_city). + +convert_list_to_c([{Name, {f, Temp}} | Rest]) -> + Converted_City = {Name, {c, (Temp -32)* 5 / 9}}, + [Converted_City | convert_list_to_c(Rest)]; + +convert_list_to_c([City | Rest]) -> + [City | convert_list_to_c(Rest)]; + +convert_list_to_c([]) -> + []. + +print_temp([{Name, {c, Temp}} | Rest]) -> + io:format("~-15w ~w c~n", [Name, Temp]), + print_temp(Rest); +print_temp([]) -> + ok. + +find_max_and_min([City | Rest]) -> + find_max_and_min(Rest, City, City). + +find_max_and_min([{Name, {c, Temp}} | Rest], + {Max_Name, {c, Max_Temp}}, + {Min_Name, {c, Min_Temp}}) -> + if + Temp > Max_Temp -> + Max_City = {Name, {c, Temp}}; % Change + true -> + Max_City = {Max_Name, {c, Max_Temp}} % Unchanged + end, + if + Temp < Min_Temp -> + Min_City = {Name, {c, Temp}}; % Change + true -> + Min_City = {Min_Name, {c, Min_Temp}} % Unchanged + end, + find_max_and_min(Rest, Max_City, Min_City); + +find_max_and_min([], Max_City, Min_City) -> + {Max_City, Min_City}. + +print_max_and_min({Max_name, {c, Max_temp}}, {Min_name, {c, Min_temp}}) -> + io:format("Max temperature was ~w c in ~w~n", [Max_temp, Max_name]), + io:format("Min temperature was ~w c in ~w~n", [Min_temp, Min_name]).]]></code><pre> +58> <input>c(tut7).</input> +{ok, tut7} +59> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow -10 c +cape_town 21.11111111111111 c +stockholm -4 c +paris -2.2222222222222223 c +london 2.2222222222222223 c +Max temperature was 21.11111111111111 c in cape_town +Min temperature was -10 c in moscow +ok</pre> + </section> + + <section> + <title>If and Case</title> + <p>The function <c>find_max_and_min</c> works out the maximum and + minimum temperature. We have introduced a new construct here + <c>if</c>. If works as follows:</p> + <code type="none"> +if + Condition 1 -> + Action 1; + Condition 2 -> + Action 2; + Condition 3 -> + Action 3; + Condition 4 -> + Action 4 +end</code> + <p>Note there is no ";" before <c>end</c>! Conditions are the same + as guards, tests which succeed or fail. Erlang starts at the top + until it finds a condition which succeeds and then it evaluates + (performs) the action following the condition and ignores all + other conditions and action before the <c>end</c>. If no + condition matches, there will be a run-time failure. A condition + which always is succeeds is the atom, <c>true</c> and this is + often used last in an <c>if</c> meaning do the action following + the <c>true</c> if all other conditions have failed.</p> + <p>The following is a short program to show the workings of + <c>if</c>.</p> + <code type="none"> +-module(tut9). +-export([test_if/2]). + +test_if(A, B) -> + if + A == 5 -> + io:format("A == 5~n", []), + a_equals_5; + B == 6 -> + io:format("B == 6~n", []), + b_equals_6; + A == 2, B == 3 -> %i.e. A equals 2 and B equals 3 + io:format("A == 2, B == 3~n", []), + a_equals_2_b_equals_3; + A == 1 ; B == 7 -> %i.e. A equals 1 or B equals 7 + io:format("A == 1 ; B == 7~n", []), + a_equals_1_or_b_equals_7 + end.</code> + <p>Testing this program gives:</p> + <pre> +60> <input>c(tut9).</input> +{ok,tut9} +61> <input>tut9:test_if(5,33).</input> +A == 5 +a_equals_5 +62> <input>tut9:test_if(33,6).</input> +B == 6 +b_equals_6 +63> <input>tut9:test_if(2, 3).</input> +A == 2, B == 3 +a_equals_2_b_equals_3 +64> <input>tut9:test_if(1, 33).</input> +A == 1 ; B == 7 +a_equals_1_or_b_equals_7 +65> <input>tut9:test_if(33, 7).</input> +A == 1 ; B == 7 +a_equals_1_or_b_equals_7 +66> <input>tut9:test_if(33, 33).</input> +** exception error: no true branch found when evaluating an if expression + in function tut9:test_if/2</pre> + <p>Notice that <c>tut9:test_if(33,33)</c> did not cause any + condition to succeed so we got the run time error + <c>if_clause</c>, here nicely formatted by the shell. See the chapter + <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual for details + of the many guard tests available. <c>case</c> is another + construct in Erlang. Recall that we wrote the + <c>convert_length</c> function as:</p> + <code type="none"> +convert_length({centimeter, X}) -> + {inch, X / 2.54}; +convert_length({inch, Y}) -> + {centimeter, Y * 2.54}.</code> + <p>We could also write the same program as:</p> + <code type="none"> +-module(tut10). +-export([convert_length/1]). + +convert_length(Length) -> + case Length of + {centimeter, X} -> + {inch, X / 2.54}; + {inch, Y} -> + {centimeter, Y * 2.54} + end.</code> + <pre> +67> <input>c(tut10).</input> +{ok,tut10} +68> <input>tut10:convert_length({inch, 6}).</input> +{centimeter,15.24} +69> <input>tut10:convert_length({centimeter, 2.5}).</input> +{inch,0.984251968503937}</pre> + <p>Notice that both <c>case</c> and <c>if</c> have <em>return values</em>, i.e. in the above example <c>case</c> returned + either <c>{inch,X/2.54}</c> or <c>{centimeter,Y*2.54}</c>. + The behaviour of <c>case</c> can also be modified by using guards. + An example should hopefully clarify this. The following example + tells us the length of a month, given the year. We need to know + the year of course, since February has 29 days in a leap year.</p> + <code type="none"> +-module(tut11). +-export([month_length/2]). + +month_length(Year, Month) -> + %% All years divisible by 400 are leap + %% Years divisible by 100 are not leap (except the 400 rule above) + %% Years divisible by 4 are leap (except the 100 rule above) + Leap = if + trunc(Year / 400) * 400 == Year -> + leap; + trunc(Year / 100) * 100 == Year -> + not_leap; + trunc(Year / 4) * 4 == Year -> + leap; + true -> + not_leap + end, + case Month of + sep -> 30; + apr -> 30; + jun -> 30; + nov -> 30; + feb when Leap == leap -> 29; + feb -> 28; + jan -> 31; + mar -> 31; + may -> 31; + jul -> 31; + aug -> 31; + oct -> 31; + dec -> 31 + end.</code> + <pre> +70> <input>c(tut11).</input> +{ok,tut11} +71> <input>tut11:month_length(2004, feb).</input> +29 +72> <input>tut11:month_length(2003, feb).</input> +28 +73> <input>tut11:month_length(1947, aug).</input> +31</pre> + </section> + + <section> + <title>Built In Functions (BIFs)</title> + <p>Built in functions BIFs are functions which for some reason is + built in to the Erlang virtual machine. BIFs often implement + functionality that is impossible to implement in Erlang or is to + inefficient to implement in Erlang. Some BIFs can be called + by use of the function name only but they are by default belonging + to the erlang module so for example the call to the BIF <c>trunc</c> + below is equivalent with a call to <c>erlang:trunc</c>.</p> + <p>As you can see, we first find out if a year is leap or not. If a + year is divisible by 400, it is a leap year. To find this out we + first divide the year by 400 and use the built in function + <c>trunc</c> (more later) to cut off any decimals. We then + multiply by 400 again and see if we get back the same value. For + example, year 2004:</p> + <code type="none"> +2004 / 400 = 5.01 +trunc(5.01) = 5 +5 * 400 = 2000</code> + <p>and we can see that we got back 2000 which is not the same as + 2004, so 2004 isn't divisible by 400. Year 2000:</p> + <code type="none"> +2000 / 400 = 5.0 +trunc(5.0) = 5 +5 * 400 = 2000</code> + <p>so we have a leap year. The next two tests if the year is + divisible by 100 or 4 are done in the same way. The first + <c>if</c> returns <c>leap</c> or <c>not_leap</c> which lands up + in the variable <c>Leap</c>. We use this variable in the guard + for <c>feb</c> in the following <c>case</c> which tells us how + long the month is.</p> + <p>This example showed the use of <c>trunc</c>, an easier way would + be to use the Erlang operator <c>rem</c> which gives the remainder + after division. For example:</p> + <pre> +74> <input>2004 rem 400.</input> +4</pre> + <p>so instead of writing</p> + <code type="none"> +trunc(Year / 400) * 400 == Year -> + leap;</code> + <p>we could write</p> + <code type="none"> +Year rem 400 == 0 -> + leap;</code> + <p>There are many other built in functions (BIF) such as + <c>trunc</c>. Only a few built in functions can be used in guards, + and you cannot use functions you have defined yourself in guards. + (see the chapter + <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual) (Aside for + advanced readers: This is to ensure that guards don't have side + effects). Let's play with a few of these functions in the shell:</p> + <pre> +75> <input>trunc(5.6).</input> +5 +76> <input>round(5.6).</input> +6 +77> <input>length([a,b,c,d]).</input> +4 +78> <input>float(5).</input> +5.0 +79> <input>is_atom(hello).</input> +true +80> <input>is_atom("hello").</input> +false +81> <input>is_tuple({paris, {c, 30}}).</input> +true +82> <input>is_tuple([paris, {c, 30}]).</input> +false</pre> + <p>All the above can be used in guards. Now for some which can't be + used in guards:</p> + <pre> +83> <input>atom_to_list(hello).</input> +"hello" +84> <input>list_to_atom("goodbye").</input> +goodbye +85> <input>integer_to_list(22).</input> +"22"</pre> + <p>The 3 BIFs above do conversions which would be difficult (or + impossible) to do in Erlang.</p> + </section> + + <section> + <title>Higher Order Functions (Funs)</title> + <p>Erlang, like most modern functional programming languages, has + higher order functions. We start with an example using the shell:</p> + <pre> +86> <input>Xf = fun(X) -> X * 2 end.</input> +#Fun<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 + working with lists are <c>foreach</c> and <c>map</c>, which are + defined as follows:</p> + <code type="none"> +foreach(Fun, [First|Rest]) -> + Fun(First), + foreach(Fun, Rest); +foreach(Fun, []) -> + ok. + +map(Fun, [First|Rest]) -> + [Fun(First)|map(Fun,Rest)]; +map(Fun, []) -> + [].</code> + <p>These two functions are provided in the standard module + <c>lists</c>. <c>foreach</c> takes a list and applies a fun to + every element in the list, <c>map</c> creates a new list by + applying a fun to every element in a list. Going back to + the shell, we start by using <c>map</c> and a fun to add 3 to + every element of a list:</p> + <pre> +88> <input>Add_3 = fun(X) -> X + 3 end.</input> +#Fun<erl_eval.5.123085357> +89> <input>lists:map(Add_3, [1,2,3]).</input> +[4,5,6]</pre> + <p>Now lets print out the temperatures in a list of cities (yet + again):</p> + <pre> +90> <input>Print_City = fun({City, {X, Temp}}) -> io:format("~-15w ~w ~w~n",</input> +<input>[City, X, Temp]) end.</input> +#Fun<erl_eval.5.123085357> +91> <input>lists:foreach(Print_City, [{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow c -10 +cape_town f 70 +stockholm c -4 +paris f 28 +london f 36 +ok</pre> + <p>We will now define a fun which can be used to go through a list + of cities and temperatures and transform them all to Celsius.</p> + <code type="none"> +-module(tut13). + +-export([convert_list_to_c/1]). + +convert_to_c({Name, {f, Temp}}) -> + {Name, {c, trunc((Temp - 32) * 5 / 9)}}; +convert_to_c({Name, {c, Temp}}) -> + {Name, {c, Temp}}. + +convert_list_to_c(List) -> + lists:map(fun convert_to_c/1, List).</code> + <pre> +92> <input>tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +[{moscow,{c,-10}}, + {cape_town,{c,21}}, + {stockholm,{c,-4}}, + {paris,{c,-2}}, + {london,{c,2}}]</pre> + <p>The <c>convert_to_c</c> function is the same as before, but we + use it as a fun:</p> + <code type="none"> +lists:map(fun convert_to_c/1, List)</code> + <p>When we use a function defined elsewhere as a fun we can refer + to it as <c>Function/Arity</c> (remember that <c>Arity</c> = + number of arguments). So in the <c>map</c> call we write + <c>lists:map(fun convert_to_c/1, List)</c>. As you can see + <c>convert_list_to_c</c> becomes much shorter and easier to + understand.</p> + <p>The standard module <c>lists</c> also contains a function + <c>sort(Fun, List)</c> where <c>Fun</c> is a fun with two + arguments. This fun should return <c>true</c> if the the first + argument is less than the second argument, or else <c>false</c>. + We add sorting to the <c>convert_list_to_c</c>:</p> + <code type="none"><![CDATA[ +-module(tut13). + +-export([convert_list_to_c/1]). + +convert_to_c({Name, {f, Temp}}) -> + {Name, {c, trunc((Temp - 32) * 5 / 9)}}; +convert_to_c({Name, {c, Temp}}) -> + {Name, {c, Temp}}. + +convert_list_to_c(List) -> + New_list = lists:map(fun convert_to_c/1, List), + lists:sort(fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> + Temp1 < Temp2 end, New_list).]]></code> + <pre> +93> <input>c(tut13).</input> +{ok,tut13} +94> <input>tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +[{moscow,{c,-10}}, + {stockholm,{c,-4}}, + {paris,{c,-2}}, + {london,{c,2}}, + {cape_town,{c,21}}]</pre> + <p>In <c>sort</c> we use the fun:</p> + <code type="none"><![CDATA[ +fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> Temp1 < Temp2 end,]]></code> + <p>Here we introduce the concept of an <em>anonymous variable</em> + "_". This is simply shorthand for a variable which is going to + get a value, but we will ignore the value. This can be used + anywhere suitable, not just in fun's. <c><![CDATA[Temp1 < Temp2]]></c> + returns <c>true</c> if <c>Temp1</c> is less than <c>Temp2</c>.</p> + </section> +</chapter> + |