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
Start
the Erlang shell (in Linux or UNIX) by starting a shell or
command interpreter in your operating system and typing
% erl Erlang R15B (erts-5.9.1) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.9.1 (abort with ^G) 1>
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.
1> 2 + 5. 7 2>
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
(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).
Here is a bit more complex calculation:
2> (42 + 77) * 66 / 3. 2618.0
Notice the use of brackets, the multiplication operator "*",
and the division operator "/", as in normal arithmetic (see
Press Control-C to shut down the Erlang system and the Erlang shell.
The following output is shown:
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution a %
Type "a" to leave the Erlang system.
Another way to shut down the Erlang system is by entering
3> halt(). %
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 named
-module(tut).
-export([double/1]).
double(X) ->
2 * X.
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
3> c(tut). {ok,tut}
The
Now run the program:
4> tut:double(10). 20
As expected, double of 10 is 20.
Now let us get back to the first two lines of the code. Erlang
programs are
written in files. Each file contains an Erlang
module. The first line of code in the module is
the module name (see
-module(tut).
Thus, the module is called tut. 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 this case the file name is
4> tut:double(10).
The second line says that the module
-export([double/1]).
The second line also says that this function can be called from
outside the module
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.
Enter the following code in a file named
-module(tut1).
-export([fac/1]).
fac(1) ->
1;
fac(N) ->
N * fac(N - 1).
So this is a module, called
The first part says that the factorial of 1 is 1.:
fac(1) ->
1;
Notice that this part ends with a semicolon ";" that indicates
that there is more of the function
The second part says that the factorial of N is N multiplied by the factorial of N - 1:
fac(N) ->
N * fac(N - 1).
Notice that this part ends with a "." saying that there are no more parts of this function.
Compile the file:
5> c(tut1). {ok,tut1}
And now calculate the factorial of 4.
6> tut1:fac(4). 24
Here the function
A function can have many arguments. Let us expand the module
-module(tut1).
-export([fac/1, mult/2]).
fac(1) ->
1;
fac(N) ->
N * fac(N - 1).
mult(X, Y) ->
X * Y.
Notice that it is also required to expand the
Compile:
7> c(tut1). {ok,tut1}
Try out the new function
8> tut1:mult(3,4). 12
In this example the numbers are integers and the arguments
in the functions in the code
Atom is another data type in Erlang. Atoms start with a small
letter (see
Enter the next program in a file named
-module(tut2).
-export([convert/2]).
convert(M, inch) ->
M / 2.54;
convert(N, centimeter) ->
N * 2.54.
Compile:
9> c(tut2). {ok,tut2}
Test:
10> tut2:convert(3, inch). 1.1811023622047243 11> tut2:convert(7, centimeter). 17.78
Notice the introduction of decimals (floating point numbers) without any explanation. Hopefully you can cope with that.
Let us see what happens if something other than
12> tut2:convert(3, miles). ** exception error: no function clause matching tut2:convert(3,miles) (tut2.erl, line 4)
The two parts of the
13> v(12). {'EXIT',{function_clause,[{tut2,convert, [3,miles], [{file,"tut2.erl"},{line,4}]}, {erl_eval,do_apply,5,[{file,"erl_eval.erl"},{line,482}]}, {shell,exprs,7,[{file,"shell.erl"},{line,666}]}, {shell,eval_exprs,7,[{file,"shell.erl"},{line,621}]}, {shell,eval_loop,3,[{file,"shell.erl"},{line,606}]}]}}
Now the
tut2:convert(3, inch).
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 tuples and are surrounded by curly brackets, "{" and "}".
So,
-module(tut3).
-export([convert_length/1]).
convert_length({centimeter, X}) ->
{inch, X / 2.54};
convert_length({inch, Y}) ->
{centimeter, Y * 2.54}.
Compile and test:
14> c(tut3). {ok,tut3} 15> tut3:convert_length({inch, 5}). {centimeter,12.7} 16> tut3:convert_length(tut3:convert_length({inch, 5})). {inch,5.0}
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.
Consider how line 16 (above) works.
The argument given to the function
Tuples can have more than two parts, in fact as many parts as you want, and contain any valid Erlang term. For example, to represent the temperature of various cities of the world:
{moscow, {c, -10}}
{cape_town, {f, 70}}
{paris, {f, 28}}
Tuples have a fixed number of items in them. Each item in a
tuple is called an element. In the tuple
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:
[{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}},
{paris, {f, 28}}, {london, {f, 36}}]
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.
A useful way of looking at parts of lists, is by using "|". This is best explained by an example using the shell:
17> [First |TheRest] = [1,2,3,4,5]. [1,2,3,4,5] 18> First. 1 19> TheRest. [2,3,4,5]
To separate the first elements of the list from the rest of the
list,
Another example:
20> [E1, E2 | R] = [1,2,3,4,5,6,7]. [1,2,3,4,5,6,7] 21> E1. 1 22> E2. 2 23> R. [3,4,5,6,7]
Here you see the use of
24> [A, B | C] = [1, 2]. [1,2] 25> A. 1 26> B. 2 27> C. []
In the previous examples, new variable names are used, instead of
reusing the old ones:
The following example shows how to find the length of a list.
Enter the following code in a file named
-module(tut4).
-export([list_length/1]).
list_length([]) ->
0;
list_length([First | Rest]) ->
1 + list_length(Rest).
Compile and test:
28> c(tut4). {ok,tut4} 29> tut4:list_length([1,2,3,4,5,6,7]). 7
Explanation:
list_length([]) ->
0;
The length of an empty list is obviously 0.
list_length([First | Rest]) ->
1 + list_length(Rest).
The length of a list with the first element
(Advanced readers only: This is not tail recursive, there is a better way to write this function.)
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.
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
30> [97,98,99]. "abc"
Maps are a set of key to value associations. These associations are encapsulated with "#{" and "}". To create an association from "key" to value 42:
> #{ "key" => 42 }.
#{"key" => 42}
Let us jump straight into the deep end with an example using some interesting features.
The following example shows how to calculate alpha blending
using maps to reference color and alpha channels. Enter the code
in a file named
-module(color).
-export([new/4, blend/2]).
-define(is_channel(V), (is_float(V) andalso V >= 0.0 andalso V =< 1.0)).
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}.
blend(Src,Dst) ->
blend(Src,Dst,alpha(Src,Dst)).
blend(Src,Dst,Alpha) when Alpha > 0.0 ->
Dst#{
red := red(Src,Dst) / Alpha,
green := green(Src,Dst) / Alpha,
blue := blue(Src,Dst) / Alpha,
alpha := Alpha
};
blend(_,Dst,_) ->
Dst#{
red := 0.0,
green := 0.0,
blue := 0.0,
alpha := 0.0
}.
alpha(#{alpha := SA}, #{alpha := DA}) ->
SA + DA*(1.0 - SA).
red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
SV*SA + DV*DA*(1.0 - SA).
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).
Compile and test:
> c(color). {ok,color} > C1 = color:new(0.3,0.4,0.5,1.0). #{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3} > C2 = color:new(1.0,0.8,0.1,0.3). #{alpha => 0.3,blue => 0.1,green => 0.8,red => 1.0} > color:blend(C1,C2). #{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3} > color:blend(C2,C1). #{alpha => 1.0,blue => 0.38,green => 0.52,red => 0.51}
This example warrants some explanation:
-define(is_channel(V), (is_float(V) andalso V >= 0.0 andalso V =< 1.0)).
First a macro
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}.
The function
By calling
The first thing
alpha(#{alpha := SA}, #{alpha := DA}) ->
SA + DA*(1.0 - SA).
The value associated with key
This is also the case for functions
red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
SV*SA + DV*DA*(1.0 - SA).
The difference here is that a check is made for two keys in each map argument. The other keys are ignored.
Finally, let us return the resulting color in
blend(Src,Dst,Alpha) when Alpha > 0.0 ->
Dst#{
red := red(Src,Dst) / Alpha,
green := green(Src,Dst) / Alpha,
blue := blue(Src,Dst) / Alpha,
alpha := Alpha
};
The
Erlang has many standard modules to help you do things. For
example, the module
% erl -man io 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- ...
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 Erlang/OTP release R9B:
http://www.erlang.org/doc/r9b/doc/index.html
It is nice to be able to do formatted output in examples, so
the next example shows a simple way to use the
31> io:format("hello world~n", []). hello world ok 32> io:format("this outputs one Erlang term: ~w~n", [hello]). this outputs one Erlang term: hello ok 33> io:format("this outputs two Erlang terms: ~w~w~n", [hello, world]). this outputs two Erlang terms: helloworld ok 34> io:format("this outputs two Erlang terms: ~w ~w~n", [hello, world]). this outputs two Erlang terms: hello world ok
The function
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.
%% 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]).
35> c(tut5). {ok,tut5} 36> tut5:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]). moscow -10 c cape_town 21.11111111111111 c stockholm -4 c paris -2.2222222222222223 c london 2.2222222222222223 c ok
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
Notice also that when testing the program from the shell, the input is spread over two lines as the line was too long.
When
Here is a function call as
Now
It can be useful to find the maximum and minimum temperature in lists like this. Before extending the program to do this, let us look at functions for finding the maximum value of the elements in a list:
-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).
37> c(tut6). {ok,tut6} 38> tut6:list_max([1,2,3,4,5,7,4,3,2,1]). 7
First notice that two functions have the same name,
In this example you walk through a list "carrying" a
value, in this case
In
Some useful operators in guards are:
(see
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
Earlier it was mentioned that a variable can only be
given a value once in its scope. In the above you see
that
Another way of creating and giving a variable a value is by using
the match operator = . So if you write
39> M = 5. 5 40> M = 6. ** exception error: no match of right hand side value 6 41> M = M + 1. ** exception error: no match of right hand side value 6 42> N = M + 1. 6
The use of the match operator is particularly useful for pulling apart Erlang terms and creating new ones.
43> {X, Y} = {paris, {f, 28}}. {paris,{f,28}} 44> X. paris 45> Y. {f,28}
Here
If you try to do the same again with another city, an error is returned:
46> {X, Y} = {london, {f, 36}}. ** exception error: no match of right hand side value {london,{f,36}}
Variables can also be used to improve the readability of
programs. For example, in function
list_max([Head|Rest], Result_so_far) when Head > Result_so_far ->
New_result_far = Head,
list_max(Rest, New_result_far);
This is possibly a little clearer.
Remember that the | operator can be used to get the head of a list:
47> [M1|T1] = [paris, london, rome]. [paris,london,rome] 48> M1. paris 49> T1. [london,rome]
The | operator can also be used to add a head to a list:
50> L1 = [madrid | T1]. [madrid,london,rome] 51> L1. [madrid,london,rome]
Now an example of this when working with lists - reversing the order of a list:
-module(tut8).
-export([reverse/1]).
reverse(List) ->
reverse(List, []).
reverse([Head | Rest], Reversed_List) ->
reverse(Rest, [Head | Reversed_List]);
reverse([], Reversed_List) ->
Reversed_List.
52> c(tut8). {ok,tut8} 53> tut8:reverse([1,2,3]). [3,2,1]
Consider how
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]
The module
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:
-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([]) ->
[].
Test the function:
54> c(tut7). {ok, tut7}. 55> tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]). [{moscow,{c,-10}}, {cape_town,{c,21.11111111111111}}, {stockholm,{c,-4}}, {paris,{c,-2.2222222222222223}}, {london,{c,2.2222222222222223}}]
Explanation:
format_temps(List_of_cities) ->
convert_list_to_c(List_of_cities).
Here
[Converted_City | convert_list_to_c(Rest)];
or:
[City | convert_list_to_c(Rest)];
This is done until the end of the list is reached, that is, the list is empty:
convert_list_to_c([]) ->
[].
Now when the list is converted, a function to print it is added:
-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.
56> c(tut7). {ok,tut7} 57> tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]). moscow -10 c cape_town 21.11111111111111 c stockholm -4 c paris -2.2222222222222223 c london 2.2222222222222223 c ok
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 needed.
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]).]]>
58> c(tut7). {ok, tut7} 59> tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]). 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
The function
if
Condition 1 ->
Action 1;
Condition 2 ->
Action 2;
Condition 3 ->
Action 3;
Condition 4 ->
Action 4
end
Notice that there is no ";" before
The following is a short program to show the workings of
-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 -> %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 -> %That is A equals 1 or B equals 7
io:format("A == 1 ; B == 7~n", []),
a_equals_1_or_b_equals_7
end.
Testing this program gives:
60> c(tut9). {ok,tut9} 61> tut9:test_if(5,33). A == 5 a_equals_5 62> tut9:test_if(33,6). B == 6 b_equals_6 63> tut9:test_if(2, 3). A == 2, B == 3 a_equals_2_b_equals_3 64> tut9:test_if(1, 33). A == 1 ; B == 7 a_equals_1_or_b_equals_7 65> tut9:test_if(33, 7). A == 1 ; B == 7 a_equals_1_or_b_equals_7 66> tut9:test_if(33, 33). ** exception error: no true branch found when evaluating an if expression in function tut9:test_if/2 (tut9.erl, line 5)
Notice that
convert_length({centimeter, X}) ->
{inch, X / 2.54};
convert_length({inch, Y}) ->
{centimeter, Y * 2.54}.
The same program can also be written as:
-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.
67> c(tut10). {ok,tut10} 68> tut10:convert_length({inch, 6}). {centimeter,15.24} 69> tut10:convert_length({centimeter, 2.5}). {inch,0.984251968503937}
Both
-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.
70> c(tut11). {ok,tut11} 71> tut11:month_length(2004, feb). 29 72> tut11:month_length(2003, feb). 28 73> tut11:month_length(1947, aug). 31
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
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
2004 / 400 = 5.01
trunc(5.01) = 5
5 * 400 = 2000
2000 is not the same as 2004, so 2004 is not divisible by 400. Year 2000:
2000 / 400 = 5.0
trunc(5.0) = 5
5 * 400 = 2000
That is, a leap year. The next two
This example showed the use of
74> 2004 rem 400. 4
So instead of writing:
trunc(Year / 400) * 400 == Year ->
leap;
it can be written:
Year rem 400 == 0 ->
leap;
There are many other BIFs such as
75> trunc(5.6). 5 76> round(5.6). 6 77> length([a,b,c,d]). 4 78> float(5). 5.0 79> is_atom(hello). true 80> is_atom("hello"). false 81> is_tuple({paris, {c, 30}}). true 82> is_tuple([paris, {c, 30}]). false
All of these can be used in guards. Now for some BIFs that cannot be used in guards:
83> atom_to_list(hello). "hello" 84> list_to_atom("goodbye"). goodbye 85> integer_to_list(22). "22"
These three BIFs do conversions that would be difficult (or impossible) to do in Erlang.
Erlang, like most modern functional programming languages, has higher-order functions. Here is an example using the shell:
86> Xf = fun(X) -> X * 2 end. #Fun<erl_eval.5.123085357> 87> Xf(5). 10
Here is defined a function that doubles
the value of a number and assigned this function to a variable. Thus
foreach(Fun, [First|Rest]) ->
Fun(First),
foreach(Fun, Rest);
foreach(Fun, []) ->
ok.
map(Fun, [First|Rest]) ->
[Fun(First)|map(Fun,Rest)];
map(Fun, []) ->
[].
These two functions are provided in the standard module
88> Add_3 = fun(X) -> X + 3 end. #Fun<erl_eval.5.123085357> 89> lists:map(Add_3, [1,2,3]). [4,5,6]
Let us (again) print the temperatures in a list of cities:
90> Print_City = fun({City, {X, Temp}}) -> io:format("~-15w ~w ~w~n", [City, X, Temp]) end. #Fun<erl_eval.5.123085357> 91> lists:foreach(Print_City, [{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]). moscow c -10 cape_town f 70 stockholm c -4 paris f 28 london f 36 ok
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.
-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).
92> tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]). [{moscow,{c,-10}}, {cape_town,{c,21}}, {stockholm,{c,-4}}, {paris,{c,-2}}, {london,{c,2}}]
The
lists:map(fun convert_to_c/1, List)
When a function defined elsewhere is used as a fun, it can be referred
to as
The standard module
{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).]]>
93> c(tut13). {ok,tut13} 94> tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]). [{moscow,{c,-10}}, {stockholm,{c,-4}}, {paris,{c,-2}}, {london,{c,2}}, {cape_town,{c,21}}]
In
Temp1 < Temp2 end,]]>
Here the concept of an anonymous variable
"_" 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.