aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/getting_started/seq_prog.xml
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/getting_started/seq_prog.xml')
-rw-r--r--system/doc/getting_started/seq_prog.xml190
1 files changed, 156 insertions, 34 deletions
diff --git a/system/doc/getting_started/seq_prog.xml b/system/doc/getting_started/seq_prog.xml
index 3830a34e5a..699b9487ed 100644
--- a/system/doc/getting_started/seq_prog.xml
+++ b/system/doc/getting_started/seq_prog.xml
@@ -31,14 +31,14 @@
<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
+ <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
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>
+ <c>erl</c>. You will see something like this.</p>
<pre>
% <input>erl</input>
Erlang R15B (erts-5.9.1) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
@@ -62,7 +62,7 @@ Eshell V5.9.1 (abort with ^G)
(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>
+ tested in several sessions.)</p>
<p>Now let's try a more complex calculation.</p>
<pre>
2> <input>(42 + 77) * 66 / 3.</input>
@@ -115,7 +115,7 @@ double(X) ->
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>
+ <p>Now let's run the program.</p>
<pre>
4> <input>tut:double(10).</input>
20</pre>
@@ -208,7 +208,7 @@ mult(X, Y) ->
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
+ in the Erlang Reference Manual). Examples of variables could be
<c>Number</c>, <c>ShoeSize</c>, <c>Age</c> etc.</p>
</section>
@@ -271,7 +271,7 @@ 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
+ <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>
@@ -309,7 +309,7 @@ convert_length({inch, Y}) ->
<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>
+ various cities of the world we could write:</p>
<code type="none">
{moscow, {c, -10}}
{cape_town, {f, 70}}
@@ -325,7 +325,7 @@ convert_length({inch, Y}) ->
<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
+ 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}},
@@ -345,7 +345,7 @@ convert_length({inch, Y}) ->
[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>
+ <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>
@@ -403,7 +403,7 @@ list_length([First | Rest]) ->
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>
+ 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
@@ -419,6 +419,129 @@ list_length([First | Rest]) ->
</section>
<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>
+<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>
+ <code type="none">
+-module(color).
+
+-export([new/4, blend/2]).
+
+-define(is_channel(V), (is_float(V) andalso V &gt;= 0.0 andalso V =&lt; 1.0)).
+
+new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
+ ?is_channel(B), ?is_channel(A) ->
+ #{red =&gt; R, green =&gt; G, blue =&gt; B, alpha =&gt; 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).</code>
+ <p>Compile (file <c>color.erl</c>) and test:</p>
+ <pre>
+> <input>c(color).</input>
+{ok,color}
+> <input>C1 = color:new(0.3,0.4,0.5,1.0).</input>
+#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
+> <input>C2 = color:new(1.0,0.8,0.1,0.3).</input>
+#{alpha => 0.3,blue => 0.1,green => 0.8,red => 1.0}
+> <input>color:blend(C1,C2).</input>
+#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
+> <input>color:blend(C2,C1).</input>
+#{alpha => 1.0,blue => 0.38,green => 0.52,red => 0.51}
+</pre>
+ <p>This example warrants some explanation:</p>
+ <code type="none">
+-define(is_channel(V), (is_float(V) andalso V &gt;= 0.0 andalso V =&lt; 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>
+ <code type="none">
+new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
+ ?is_channel(B), ?is_channel(A) ->
+ #{red =&gt; R, green =&gt; G, blue =&gt; B, alpha =&gt; 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>
+ <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>
+ <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>
+ <code type="none">
+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
+ };</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>
+ </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
@@ -450,10 +573,9 @@ http://www.erlang.org/doc/r9b/doc/index.html</code>
<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>
+ 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>
<pre>
31> <input>io:format("hello world~n", []).</input>
hello world
@@ -550,7 +672,7 @@ ok</pre>
<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
+ 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. [],
@@ -614,12 +736,12 @@ list_max([Head|Rest], Result_so_far) ->
the next part of the function.</p>
<p>Some useful operators in guards are, &lt; less than, &gt;
greater than, == equal, &gt;= greater or equal, =&lt; less or
- equal, /= not equal. (see the chapter
- <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual).</p>
+ equal, /= not equal. (See the chapter
+ <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual.)</p>
<p>To change the above program to one which works out the minimum
value of the element in a list, all we would need to do is to
write &lt; instead of &gt;. (But it would be wise to change
- the name of the function to <c>list_min</c> :-).</p>
+ 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
@@ -723,7 +845,7 @@ reverse([], [3,2,1]) =>
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
+ <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>
<code type="none">
@@ -767,7 +889,7 @@ format_temps(List_of_cities) ->
<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>
+ the list is empty):</p>
<code type="none">
convert_list_to_c([]) ->
[].</code>
@@ -1029,13 +1151,13 @@ month_length(Year, Month) ->
<section>
<title>Built In Functions (BIFs)</title>
- <p>Built in functions BIFs are functions which for some reason is
+ <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 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>
+ 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>
+ 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
@@ -1052,23 +1174,23 @@ trunc(5.01) = 5
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
+ <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
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
+ <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>
+ <p>so instead of writing:</p>
<code type="none">
trunc(Year / 400) * 400 == Year ->
leap;</code>
- <p>we could write</p>
+ <p>we could write:</p>
<code type="none">
Year rem 400 == 0 ->
leap;</code>
@@ -1078,7 +1200,7 @@ Year rem 400 == 0 ->
(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>
+ effects.) Let's play with a few of these functions in the shell:</p>
<pre>
75> <input>trunc(5.6).</input>
5
@@ -1145,7 +1267,7 @@ map(Fun, []) ->
#Fun&lt;erl_eval.5.123085357&gt;
89> <input>lists:map(Add_3, [1,2,3]).</input>
[4,5,6]</pre>
- <p>Now lets print out the temperatures in a list of cities (yet
+ <p>Now let's 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>