diff options
author | Björn Gustavsson <[email protected]> | 2015-03-16 11:48:38 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2015-03-16 11:48:38 +0100 |
commit | b90108ba566ff3754ebef667d2375be4d41d044e (patch) | |
tree | 4f6f4221371035ed700dcf4ef76b3d4018733eac /system/doc/programming_examples | |
parent | a2481e05c8009962d5a3ec56eaeffc053718ec7f (diff) | |
parent | 0a1d39481440eb033f48fbbc8889bc99eda85d41 (diff) | |
download | otp-b90108ba566ff3754ebef667d2375be4d41d044e.tar.gz otp-b90108ba566ff3754ebef667d2375be4d41d044e.tar.bz2 otp-b90108ba566ff3754ebef667d2375be4d41d044e.zip |
Merge branch 'bjorn/system-documentation'
* bjorn/system-documentation:
Replace "lambda head" with "fun" in compiler warning
Remove an historical note about fun representation before R6B
Replace mention of a tuple fun with an external fun
Update Interoperability Tutorial
Update System Principles
Update Erlang Reference Manual
Update Getting Started
Update Programming Examples
Update OAM Principles
Update Installation Guide
Update Embedded Systems User's Guide
Update Efficiency Guide
Update Design Principles
Diffstat (limited to 'system/doc/programming_examples')
-rw-r--r-- | system/doc/programming_examples/bit_syntax.xml | 210 | ||||
-rw-r--r-- | system/doc/programming_examples/funs.xmlsrc | 288 | ||||
-rw-r--r-- | system/doc/programming_examples/list_comprehensions.xml | 86 | ||||
-rw-r--r-- | system/doc/programming_examples/part.xml | 5 | ||||
-rw-r--r-- | system/doc/programming_examples/records.xml | 88 |
5 files changed, 351 insertions, 326 deletions
diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml index fb321c1ba9..7ede5b71f9 100644 --- a/system/doc/programming_examples/bit_syntax.xml +++ b/system/doc/programming_examples/bit_syntax.xml @@ -31,62 +31,64 @@ <section> <title>Introduction</title> - <p>In Erlang a Bin is used for constructing binaries and matching + <p>In Erlang, a Bin is used for constructing binaries and matching binary patterns. A Bin is written with the following syntax:</p> <code type="none"><![CDATA[ <<E1, E2, ... En>>]]></code> - <p>A Bin is a low-level sequence of bits or bytes. The purpose of a Bin is - to be able to, from a high level, construct a binary,</p> + <p>A Bin is a low-level sequence of bits or bytes. + The purpose of a Bin is to enable construction of binaries:</p> <code type="none"><![CDATA[ Bin = <<E1, E2, ... En>>]]></code> - <p>in which case all elements must be bound, or to match a binary,</p> + <p>All elements must be bound. Or match a binary:</p> <code type="none"><![CDATA[ <<E1, E2, ... En>> = Bin ]]></code> - <p>where <c>Bin</c> is bound, and where the elements are bound or + <p>Here, <c>Bin</c> is bound and the elements are bound or unbound, as in any match.</p> - <p>In R12B, a Bin need not consist of a whole number of bytes.</p> + <p>Since Erlang R12B, a Bin does not need to consist of a whole number of bytes.</p> <p>A <em>bitstring</em> is a sequence of zero or more bits, where - the number of bits doesn't need to be divisible by 8. If the number + the number of bits does not need to be divisible by 8. If the number of bits is divisible by 8, the bitstring is also a binary.</p> <p>Each element specifies a certain <em>segment</em> of the bitstring. A segment is a set of contiguous bits of the binary (not necessarily on a byte boundary). The first element specifies the initial segment, the second element specifies the following - segment etc.</p> - <p>The following examples illustrate how binaries are constructed + segment, and so on.</p> + <p>The following examples illustrate how binaries are constructed, or matched, and how elements and tails are specified.</p> <section> <title>Examples</title> - <p><em>Example 1: </em>A binary can be constructed from a set of + <p><em>Example 1:</em> A binary can be constructed from a set of constants or a string literal:</p> <code type="none"><![CDATA[ Bin11 = <<1, 17, 42>>, Bin12 = <<"abc">>]]></code> - <p>yields binaries of size 3; <c>binary_to_list(Bin11)</c> - evaluates to <c>[1, 17, 42]</c>, and - <c>binary_to_list(Bin12)</c> evaluates to <c>[97, 98, 99]</c>.</p> - <p><em>Example 2: </em>Similarly, a binary can be constructed + <p>This gives two binaries of size 3, with the following evaluations:</p> + <list type="bulleted"> + <item><c>binary_to_list(Bin11)</c> evaluates to <c>[1, 17, 42]</c>.</item> + <item><c>binary_to_list(Bin12)</c> evaluates to <c>[97, 98, 99]</c>.</item> + </list> + <p><em>Example 2:</em>Similarly, a binary can be constructed from a set of bound variables:</p> <code type="none"><![CDATA[ A = 1, B = 17, C = 42, Bin2 = <<A, B, C:16>>]]></code> - <p>yields a binary of size 4, and <c>binary_to_list(Bin2)</c> - evaluates to <c>[1, 17, 00, 42]</c> too. Here we used a - <em>size expression</em> for the variable <c>C</c> in order to + <p>This gives a binary of size 4. + Here, a <em>size expression</em> is used for the variable <c>C</c> to specify a 16-bits segment of <c>Bin2</c>.</p> - <p><em>Example 3: </em>A Bin can also be used for matching: if + <p><c>binary_to_list(Bin2)</c> evaluates to <c>[1, 17, 00, 42]</c>.</p> + <p><em>Example 3:</em> A Bin can also be used for matching. <c>D</c>, <c>E</c>, and <c>F</c> are unbound variables, and - <c>Bin2</c> is bound as in the former example,</p> + <c>Bin2</c> is bound, as in Example 2:</p> <code type="none"><![CDATA[ <<D:16, E, F/binary>> = Bin2]]></code> - <p>yields <c>D = 273</c>, <c>E = 00</c>, and F binds to a binary + <p>This gives <c>D = 273</c>, <c>E = 00</c>, and F binds to a binary of size 1: <c>binary_to_list(F) = [42]</c>.</p> <p><em>Example 4:</em> The following is a more elaborate example - of matching, where <c>Dgram</c> is bound to the consecutive - bytes of an IP datagram of IP protocol version 4, and where we - want to extract the header and the data of the datagram:</p> + of matching. Here, <c>Dgram</c> is bound to the consecutive + bytes of an IP datagram of IP protocol version 4. The ambition is + to extract the header and the data of the datagram:</p> <code type="none"><![CDATA[ -define(IP_VERSION, 4). -define(IP_MIN_HDR_LEN, 5). @@ -102,53 +104,59 @@ case Dgram of <<Opts:OptsLen/binary,Data/binary>> = RestDgram, ... end.]]></code> - <p>Here the segment corresponding to the <c>Opts</c> variable - has a <em>type modifier</em> specifying that <c>Opts</c> should + <p>Here, the segment corresponding to the <c>Opts</c> variable + has a <em>type modifier</em>, specifying that <c>Opts</c> is to bind to a binary. All other variables have the default type equal to unsigned integer.</p> - <p>An IP datagram header is of variable length, and its length - - measured in the number of 32-bit words - is given in - the segment corresponding to <c>HLen</c>, the minimum value of - which is 5. It is the segment corresponding to <c>Opts</c> - that is variable: if <c>HLen</c> is equal to 5, <c>Opts</c> - will be an empty binary.</p> + <p>An IP datagram header is of variable length. This length is + measured in the number of 32-bit words and is given in + the segment corresponding to <c>HLen</c>. The minimum value of + <c>HLen</c> is 5. It is the segment corresponding to <c>Opts</c> + that is variable, so if <c>HLen</c> is equal to 5, <c>Opts</c> + becomes an empty binary.</p> <p>The tail variables <c>RestDgram</c> and <c>Data</c> bind to - binaries, as all tail variables do. Both may bind to empty + binaries, as all tail variables do. Both can bind to empty binaries.</p> - <p>If the first 4-bits segment of <c>Dgram</c> is not equal to - 4, or if <c>HLen</c> is less than 5, or if the size of - <c>Dgram</c> is less than <c>4*HLen</c>, the match of - <c>Dgram</c> fails.</p> + <p>The match of <c>Dgram</c> fails if one of the following occurs:</p> + <list type="bulleted"> + <item>The first 4-bits segment of <c>Dgram</c> is not equal to 4.</item> + <item><c>HLen</c> is less than 5.</item> + <item>The size of <c>Dgram</c> is less than <c>4*HLen</c>.</item> + </list> </section> </section> <section> - <title>A Lexical Note</title> - <p>Note that "<c><![CDATA[B=<<1>>]]></c>" will be interpreted as + <title>Lexical Note</title> + <p>Notice that "<c><![CDATA[B=<<1>>]]></c>" will be interpreted as "<c><![CDATA[B =< <1>>]]></c>", which is a syntax error. - The correct way to write the expression is - "<c><![CDATA[B = <<1>>]]></c>".</p> + The correct way to write the expression is: + <c><![CDATA[B = <<1>>]]></c>.</p> </section> <section> <title>Segments</title> <p>Each segment has the following general syntax:</p> <p><c>Value:Size/TypeSpecifierList</c></p> - <p>Both the <c>Size</c> and the <c>TypeSpecifier</c> or both may be - omitted; thus the following variations are allowed:</p> - <p><c>Value</c></p> - <p><c>Value:Size</c></p> - <p><c>Value/TypeSpecifierList</c></p> - <p>Default values will be used for missing specifications. - The default values are described in the section + <p>The <c>Size</c> or the <c>TypeSpecifier</c>, or both, can be + omitted. Thus, the following variants are allowed:</p> + <list type="bulleted"> + <item><c>Value</c></item> + <item><c>Value:Size</c></item> + <item><c>Value/TypeSpecifierList</c></item> + </list> + <p>Default values are used when specifications are missing. + The default values are described in <seealso marker="#Defaults">Defaults</seealso>.</p> - <p>Used in binary construction, the <c>Value</c> part is any - expression. Used in binary matching, the <c>Value</c> part must - be a literal or variable. You can read more about - the <c>Value</c> part in the section about constructing - binaries and matching binaries.</p> + <p>The <c>Value</c> part is any expression, when used in binary construction. + Used in binary matching, the <c>Value</c> part must + be a literal or a variable. For more information about + the <c>Value</c> part, see + <seealso marker="#Constructing Binaries and Bitstrings">Constructing Binaries and Bitstrings</seealso> + and + <seealso marker="#Matching Binaries">Matching Binaries</seealso>.</p> <p>The <c>Size</c> part of the segment multiplied by the unit in - the <c>TypeSpecifierList</c> (described below) gives the number + <c>TypeSpecifierList</c> (described later) gives the number of bits for the segment. In construction, <c>Size</c> is any expression that evaluates to an integer. In matching, <c>Size</c> must be a constant expression or a variable.</p> @@ -160,22 +168,22 @@ end.]]></code> <c>binary</c>.</item> <tag>Signedness</tag> <item>The signedness specification can be either <c>signed</c> - or <c>unsigned</c>. Note that signedness only matters for + or <c>unsigned</c>. Notice that signedness only matters for matching.</item> <tag>Endianness</tag> <item>The endianness specification can be either <c>big</c>, <c>little</c>, or <c>native</c>. Native-endian means that - the endian will be resolved at load time to be either + the endian is resolved at load time, to be either big-endian or little-endian, depending on what is "native" for the CPU that the Erlang machine is run on.</item> <tag>Unit</tag> <item>The unit size is given as <c>unit:IntegerLiteral</c>. - The allowed range is 1-256. It will be multiplied by + The allowed range is 1-256. It is multiplied by the <c>Size</c> specifier to give the effective size of - the segment. In R12B, the unit size specifies the alignment - for binary segments without size (examples will follow).</item> + the segment. Since Erlang R12B, the unit size specifies the alignment + for binary segments without size.</item> </taglist> - <p>Example:</p> + <p><em>Example:</em></p> <code type="none"> X:4/little-signed-integer-unit:8</code> <p>This element has a total size of 4*8 = 32 bits, and it contains @@ -184,13 +192,14 @@ X:4/little-signed-integer-unit:8</code> <section> <title>Defaults</title> - <p><marker id="Defaults"></marker>The default type for a segment is integer. The default + <p><marker id="Defaults"></marker>The default type for + a segment is integer. The default type does not depend on the value, even if the value is a - literal. For instance, the default type in '<c><![CDATA[<<3.14>>]]></c>' is + literal. For example, the default type in <c><![CDATA[<<3.14>>]]></c> is integer, not float.</p> <p>The default <c>Size</c> depends on the type. For integer it is 8. For float it is 64. For binary it is all of the binary. In - matching, this default value is only valid for the very last + matching, this default value is only valid for the last element. All other binary elements in matching must have a size specification.</p> <p>The default unit depends on the the type. For <c>integer</c>, @@ -201,61 +210,60 @@ X:4/little-signed-integer-unit:8</code> <section> <title>Constructing Binaries and Bitstrings</title> + <marker id="Constructing Binaries and Bitstrings"></marker> <p>This section describes the rules for constructing binaries using the bit syntax. Unlike when constructing lists or tuples, the construction of a binary can fail with a <c>badarg</c> exception.</p> <p>There can be zero or more segments in a binary to be - constructed. The expression '<c><![CDATA[<<>>]]></c>' constructs a zero + constructed. The expression <c><![CDATA[<<>>]]></c> constructs a zero length binary.</p> <p>Each segment in a binary can consist of zero or more bits. There are no alignment rules for individual segments of type <c>integer</c> and <c>float</c>. For binaries and bitstrings without size, the unit specifies the alignment. Since the default alignment for the <c>binary</c> type is 8, the size of a binary - segment must be a multiple of 8 bits (i.e. only whole bytes). - Example:</p> + segment must be a multiple of 8 bits, that is, only whole bytes.</p> + <p><em>Example:</em></p> <code type="none"><![CDATA[ <<Bin/binary,Bitstring/bitstring>>]]></code> <p>The variable <c>Bin</c> must contain a whole number of bytes, because the <c>binary</c> type defaults to <c>unit:8</c>. - A <c>badarg</c> exception will be generated if <c>Bin</c> would - consist of (for instance) 17 bits.</p> + A <c>badarg</c> exception is generated if <c>Bin</c> + consist of, for example, 17 bits.</p> - <p>On the other hand, the variable <c>Bitstring</c> may consist of - any number of bits, for instance 0, 1, 8, 11, 17, 42, and so on, - because the default <c>unit</c> for bitstrings is 1.</p> + <p>The <c>Bitstring</c> variable can consist of + any number of bits, for example, 0, 1, 8, 11, 17, 42, and so on. + This is because the default <c>unit</c> for bitstrings is 1.</p> - <warning><p>For clarity, it is recommended not to change the unit - size for binaries, but to use <c>binary</c> when you need byte - alignment, and <c>bitstring</c> when you need bit alignment.</p></warning> + <p>For clarity, it is recommended not to change the unit + size for binaries. Instead, use <c>binary</c> when you need byte alignment + and <c>bitstring</c> when you need bit alignment.</p> - <p>The following example</p> + <p>The following example successfully constructs a bitstring of 7 bits, + provided that all of X and Y are integers:</p> <code type="none"><![CDATA[ <<X:1,Y:6>>]]></code> - <p>will successfully construct a bitstring of 7 bits. - (Provided that all of X and Y are integers.)</p> - <p>As noted earlier, segments have the following general syntax:</p> + <p>As mentioned earlier, segments have the following general syntax:</p> <p><c>Value:Size/TypeSpecifierList</c></p> <p>When constructing binaries, <c>Value</c> and <c>Size</c> can be any Erlang expression. However, for syntactical reasons, both <c>Value</c> and <c>Size</c> must be enclosed in parenthesis if the expression consists of anything more than a single literal - or variable. The following gives a compiler syntax error:</p> + or a variable. The following gives a compiler syntax error:</p> <code type="none"><![CDATA[ <<X+1:8>>]]></code> - <p>This expression must be rewritten to</p> + <p>This expression must be rewritten into the following, + to be accepted by the compiler:</p> <code type="none"><![CDATA[ <<(X+1):8>>]]></code> - <p>in order to be accepted by the compiler.</p> <section> <title>Including Literal Strings</title> - <p>As syntactic sugar, an literal string may be written instead - of a element.</p> + <p>A literal string can be written instead of an element:</p> <code type="none"><![CDATA[ <<"hello">>]]></code> - <p>which is syntactic sugar for</p> + <p>This is syntactic sugar for the following:</p> <code type="none"><![CDATA[ <<$h,$e,$l,$l,$o>>]]></code> </section> @@ -263,29 +271,30 @@ X:4/little-signed-integer-unit:8</code> <section> <title>Matching Binaries</title> - <p>This section describes the rules for matching binaries using + <marker id="Matching Binaries"></marker> + <p>This section describes the rules for matching binaries, using the bit syntax.</p> <p>There can be zero or more segments in a binary pattern. - A binary pattern can occur in every place patterns are allowed, - also inside other patterns. Binary patterns cannot be nested.</p> - <p>The pattern '<c><![CDATA[<<>>]]></c>' matches a zero length binary.</p> - <p>Each segment in a binary can consist of zero or more bits.</p> - <p>A segment of type <c>binary</c> must have a size evenly - divisible by 8 (or divisible by the unit size, if the unit size has been changed).</p> - <p>A segment of type <c>bitstring</c> has no restrictions on the size.</p> - <p>As noted earlier, segments have the following general syntax:</p> + A binary pattern can occur wherever patterns are allowed, + including inside other patterns. Binary patterns cannot be nested. + The pattern <c><![CDATA[<<>>]]></c> matches a zero length binary.</p> + <p>Each segment in a binary can consist of zero or more bits. + A segment of type <c>binary</c> must have a size evenly divisible by 8 + (or divisible by the unit size, if the unit size has been changed). + A segment of type <c>bitstring</c> has no restrictions on the size.</p> + <p>As mentioned earlier, segments have the following general syntax:</p> <p><c>Value:Size/TypeSpecifierList</c></p> - <p>When matching <c>Value</c> value must be either a variable or - an integer or floating point literal. Expressions are not + <p>When matching <c>Value</c>, value must be either a variable or + an integer, or a floating point literal. Expressions are not allowed.</p> <p><c>Size</c> must be an integer literal, or a previously bound - variable. Note that the following is not allowed:</p> + variable. The following is not allowed:</p> <code type="none"><![CDATA[ foo(N, <<X:N,T/binary>>) -> {X,T}.]]></code> <p>The two occurrences of <c>N</c> are not related. The compiler will complain that the <c>N</c> in the size field is unbound.</p> - <p>The correct way to write this example is like this:</p> + <p>The correct way to write this example is as follows:</p> <code type="none"><![CDATA[ foo(N, Bin) -> <<X:N,T/binary>> = Bin, @@ -303,14 +312,14 @@ foo(<<A:8,Rest/binary>>) ->]]></code> without size:</p> <code type="none"><![CDATA[ foo(<<A:8,Rest/bitstring>>) ->]]></code> - <p>There is no restriction on the number of bits in the tail.</p> + <p>There are no restrictions on the number of bits in the tail.</p> </section> </section> <section> <title>Appending to a Binary</title> - <p>In R12B, the following function for creating a binary out of - a list of triples of integers is now efficient:</p> + <p>Since Erlang R12B, the following function for creating a binary out of + a list of triples of integers is efficient:</p> <code type="none"><![CDATA[ triples_to_bin(T) -> triples_to_bin(T, <<>>). @@ -321,7 +330,8 @@ triples_to_bin([], Acc) -> Acc.]]></code> <p>In previous releases, this function was highly inefficient, because the binary constructed so far (<c>Acc</c>) was copied in each recursion step. - That is no longer the case. See the Efficiency Guide for more information.</p> + That is no longer the case. For more information, see + <seealso marker="doc/efficiency_guide">Efficiency Guide</seealso>.</p> </section> </chapter> diff --git a/system/doc/programming_examples/funs.xmlsrc b/system/doc/programming_examples/funs.xmlsrc index 7bfac9db8c..d4c32bc854 100644 --- a/system/doc/programming_examples/funs.xmlsrc +++ b/system/doc/programming_examples/funs.xmlsrc @@ -30,146 +30,138 @@ </header> <section> - <title>Example 1 - map</title> - <p>If we want to double every element in a list, we could write a - function named <c>double</c>:</p> + <title>map</title> + <p>The following function, <c>double</c>, doubles every element in a list:</p> <code type="none"> double([H|T]) -> [2*H|double(T)]; double([]) -> [].</code> - <p>This function obviously doubles the argument entered as input - as follows:</p> + <p>Hence, the argument entered as input is doubled as follows:</p> <pre> > <input>double([1,2,3,4]).</input> [2,4,6,8]</pre> - <p>We now add the function <c>add_one</c>, which adds one to every + <p>The following function, <c>add_one</c>, adds one to every element in a list:</p> <code type="none"> add_one([H|T]) -> [H+1|add_one(T)]; add_one([]) -> [].</code> - <p>These functions, <c>double</c> and <c>add_one</c>, have a very - similar structure. We can exploit this fact and write a function - <c>map</c> which expresses this similarity:</p> + <p>The functions <c>double</c> and <c>add_one</c> have a + similar structure. This can be used by writing a function + <c>map</c> that expresses this similarity:</p> <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> - <p>We can now express the functions <c>double</c> and - <c>add_one</c> in terms of <c>map</c> as follows:</p> + <p>The functions <c>double</c> and <c>add_one</c> can now be expressed + in terms of <c>map</c> as follows:</p> <code type="none"> double(L) -> map(fun(X) -> 2*X end, L). add_one(L) -> map(fun(X) -> 1 + X end, L).</code> - <p><c>map(F, List)</c> is a function which takes a function - <c>F</c> and a list <c>L</c> as arguments and returns the new - list which is obtained by applying <c>F</c> to each of + <p><c>map(F, List)</c> is a function that takes a function + <c>F</c> and a list <c>L</c> as arguments and returns a new + list, obtained by applying <c>F</c> to each of the elements in <c>L</c>.</p> <p>The process of abstracting out the common features of a number - of different programs is called procedural abstraction. - Procedural abstraction can be used in order to write several - different functions which have a similar structure, but differ - only in some minor detail. This is done as follows:</p> + of different programs is called <em>procedural abstraction</em>. + Procedural abstraction can be used to write several + different functions that have a similar structure, but differ + in some minor detail. This is done as follows:</p> <list type="ordered"> - <item>write one function which represents the common features of - these functions</item> - <item>parameterize the difference in terms of functions which + <item><em>Step 1.</em> Write one function that represents the common features of + these functions.</item> + <item><em>Step 2.</em> Parameterize the difference in terms of functions that are passed as arguments to the common function.</item> </list> </section> <section> - <title>Example 2 - foreach</title> - <p>This example illustrates procedural abstraction. Initially, we - show the following two examples written as conventional - functions:</p> - <list type="ordered"> - <item>all elements of a list are printed onto a stream</item> - <item>a message is broadcast to a list of processes.</item> - </list> + <title>foreach</title> + <p>This section illustrates procedural abstraction. Initially, + the following two examples are written as conventional + functions.</p> + <p>This function prints all elements of a list onto a stream:</p> <code type="none"> print_list(Stream, [H|T]) -> io:format(Stream, "~p~n", [H]), print_list(Stream, T); print_list(Stream, []) -> true.</code> + <p>This function broadcasts a message to a list of processes:</p> <code type="none"> broadcast(Msg, [Pid|Pids]) -> Pid ! Msg, broadcast(Msg, Pids); broadcast(_, []) -> true.</code> - <p>Both these functions have a very similar structure. They both - iterate over a list doing something to each element in the list. - The "something" has to be carried round as an extra argument to - the function which does this.</p> + <p>These two functions have a similar structure. They both + iterate over a list and do something to each element in the list. + The "something" is passed on as an extra argument to + the function that does this.</p> <p>The function <c>foreach</c> expresses this similarity:</p> <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> - <p>Using <c>foreach</c>, <c>print_list</c> becomes:</p> + <p>Using the function <c>foreach</c>, the function <c>print_list</c> becomes:</p> <code type="none"> foreach(fun(H) -> io:format(S, "~p~n",[H]) end, L)</code> - <p><c>broadcast</c> becomes:</p> + <p>Using the function <c>foreach</c>, the function <c>broadcast</c> becomes:</p> <code type="none"> foreach(fun(Pid) -> Pid ! M end, L)</code> <p><c>foreach</c> is evaluated for its side-effect and not its value. <c>foreach(Fun ,L)</c> calls <c>Fun(X)</c> for each element <c>X</c> in <c>L</c> and the processing occurs in - the order in which the elements were defined in <c>L</c>. + the order that the elements were defined in <c>L</c>. <c>map</c> does not define the order in which its elements are processed.</p> </section> <section> - <title>The Syntax of Funs</title> - <p>Funs are written with the syntax:</p> + <title>Syntax of Funs</title> + <p>Funs are written with the following syntax:</p> <code type="none"> F = fun (Arg1, Arg2, ... ArgN) -> ... end</code> <p>This creates an anonymous function of <c>N</c> arguments and binds it to the variable <c>F</c>.</p> - <p>If we have already written a function in the same module and - wish to pass this function as an argument, we can use - the following syntax:</p> + <p>Another function, <c>FunctionName</c>, written in the same module, + can be passed as an argument, using the following syntax:</p> <code type="none"> F = fun FunctionName/Arity</code> - <p>With this form of function reference, the function which is + <p>With this form of function reference, the function that is referred to does not need to be exported from the module.</p> - <p>We can also refer to a function defined in a different module + <p>It is also possible to refer to a function defined in a different module, with the following syntax:</p> <code type="none"> -F = {Module, FunctionName}</code> +F = fun Module:FunctionName/Arity</code> <p>In this case, the function must be exported from the module in question.</p> - <p>The follow program illustrates the different ways of creating + <p>The following program illustrates the different ways of creating funs:</p> <codeinclude file="fun_test.erl" tag="%1" type="erl"></codeinclude> - <p>We can evaluate the fun <c>F</c> with the syntax:</p> + <p>The fun <c>F</c> can be evaluated with the following syntax:</p> <code type="none"> F(Arg1, Arg2, ..., Argn)</code> <p>To check whether a term is a fun, use the test - <c>is_function/1</c> in a guard. Example:</p> + <c>is_function/1</c> in a guard.</p> + <p><em>Example:</em></p> <code type="none"> f(F, Args) when is_function(F) -> apply(F, Args); f(N, _) when is_integer(N) -> N.</code> - <p>Funs are a distinct type. The BIFs erlang:fun_info/1,2 can + <p>Funs are a distinct type. The BIFs <c>erlang:fun_info/1,2</c> can be used to retrieve information about a fun, and the BIF - erlang:fun_to_list/1 returns a textual representation of a fun. - The check_process_code/2 BIF returns true if the process + <c>erlang:fun_to_list/1</c> returns a textual representation of a fun. + The <c>check_process_code/2</c> BIF returns <c>true</c> if the process contains funs that depend on the old version of a module.</p> - <note> - <p>In OTP R5 and earlier releases, funs were represented using - tuples.</p> - </note> </section> <section> <title>Variable Bindings Within a Fun</title> - <p>The scope rules for variables which occur in funs are as + <p>The scope rules for variables that occur in funs are as follows:</p> <list type="bulleted"> - <item>All variables which occur in the head of a fun are assumed + <item>All variables that occur in the head of a fun are assumed to be "fresh" variables.</item> - <item>Variables which are defined before the fun, and which + <item>Variables that are defined before the fun, and that occur in function calls or guard tests within the fun, have the values they had outside the fun.</item> - <item>No variables may be exported from a fun.</item> + <item>Variables cannot be exported from a fun.</item> </list> <p>The following examples illustrate these rules:</p> <code type="none"> @@ -177,12 +169,13 @@ print_list(File, List) -> {ok, Stream} = file:open(File, write), foreach(fun(X) -> io:format(Stream,"~p~n",[X]) end, List), file:close(Stream).</code> - <p>In the above example, the variable <c>X</c> which is defined in - the head of the fun is a new variable. The value of the variable - <c>Stream</c> which is used within within the fun gets its value + <p>Here, the variable <c>X</c>, defined in + the head of the fun, is a new variable. The variable + <c>Stream</c>, which is used within the fun, gets its value from the <c>file:open</c> line.</p> - <p>Since any variable which occurs in the head of a fun is - considered a new variable it would be equally valid to write:</p> + <p>As any variable that occurs in the head of a fun is + considered a new variable, it is equally valid to write + as follows:</p> <code type="none"> print_list(File, List) -> {ok, Stream} = file:open(File, write), @@ -190,21 +183,21 @@ print_list(File, List) -> io:format(Stream,"~p~n",[File]) end, List), file:close(Stream).</code> - <p>In this example, <c>File</c> is used as the new variable - instead of <c>X</c>. This is rather silly since code in the body - of the fun cannot refer to the variable <c>File</c> which is - defined outside the fun. Compiling this example will yield - the diagnostic:</p> + <p>Here, <c>File</c> is used as the new variable + instead of <c>X</c>. This is not so wise because code in the fun + body cannot refer to the variable <c>File</c>, which is + defined outside of the fun. Compiling this example gives + the following diagnostic:</p> <code type="none"> ./FileName.erl:Line: Warning: variable 'File' - shadowed in 'lambda head'</code> - <p>This reminds us that the variable <c>File</c> which is defined - inside the fun collides with the variable <c>File</c> which is + shadowed in 'fun'</code> + <p>This indicates that the variable <c>File</c>, which is defined + inside the fun, collides with the variable <c>File</c>, which is defined outside the fun.</p> <p>The rules for importing variables into a fun has the consequence - that certain pattern matching operations have to be moved into + that certain pattern matching operations must be moved into guard expressions and cannot be written in the head of the fun. - For example, we might write the following code if we intend + For example, you might write the following code if you intend the first clause of <c>F</c> to be evaluated when the value of its argument is <c>Y</c>:</p> <code type="none"> @@ -216,7 +209,7 @@ f(...) -> ... end, ...) ...</code> - <p>instead of</p> + <p>instead of writng the following code:</p> <code type="none"> f(...) -> Y = ... @@ -229,35 +222,37 @@ f(...) -> </section> <section> - <title>Funs and the Module Lists</title> + <title>Funs and Module Lists</title> <p>The following examples show a dialogue with the Erlang shell. All the higher order functions discussed are exported from the module <c>lists</c>.</p> <section> <title>map</title> + <p><c>map</c> takes a function of one argument and a list of terms:</p> <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> - <p><c>map</c> takes a function of one argument and a list of - terms. It returns the list obtained by applying the function + <p>It returns the list obtained by applying the function to every argument in the list.</p> + <p>When a new fun is defined in the shell, the value of the fun + is printed as <c><![CDATA[Fun#<erl_eval>]]></c>:</p> <pre> > <input>Double = fun(X) -> 2 * X end.</input> #Fun<erl_eval.6.72228031> > <input>lists:map(Double, [1,2,3,4,5]).</input> [2,4,6,8,10]</pre> - <p>When a new fun is defined in the shell, the value of the Fun - is printed as <c><![CDATA[Fun#<erl_eval>]]></c>.</p> + </section> <section> <title>any</title> - <codeinclude file="funs1.erl" tag="%4" type="erl"></codeinclude> <p><c>any</c> takes a predicate <c>P</c> of one argument and a - list of terms. A predicate is a function which returns - <c>true</c> or <c>false</c>. <c>any</c> is true if there is a - term <c>X</c> in the list such that <c>P(X)</c> is <c>true</c>.</p> - <p>We define a predicate <c>Big(X)</c> which is <c>true</c> if - its argument is greater that 10.</p> + list of terms:</p> + <codeinclude file="funs1.erl" tag="%4" type="erl"></codeinclude> + <p>A predicate is a function that returns <c>true</c> or <c>false</c>. + <c>any</c> is <c>true</c> if there is a term <c>X</c> in the list such that + <c>P(X)</c> is <c>true</c>.</p> + <p>A predicate <c>Big(X)</c> is defined, which is <c>true</c> if + its argument is greater that 10:</p> <pre> > <input>Big = fun(X) -> if X > 10 -> true; true -> false end end.</input> #Fun<erl_eval.6.72228031> @@ -269,9 +264,10 @@ true</pre> <section> <title>all</title> + <p><c>all</c> has the same arguments as <c>any</c>:</p> <codeinclude file="funs1.erl" tag="%3" type="erl"></codeinclude> - <p><c>all</c> has the same arguments as <c>any</c>. It is true - if the predicate applied to all elements in the list is true.</p> + <p>It is <c>true</c> + if the predicate applied to all elements in the list is <c>true</c>.</p> <pre> > <input>lists:all(Big, [1,2,3,4,12,6]).</input> false @@ -281,11 +277,12 @@ true</pre> <section> <title>foreach</title> - <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> <p><c>foreach</c> takes a function of one argument and a list of - terms. The function is applied to each argument in the list. - <c>foreach</c> returns <c>ok</c>. It is used for its - side-effect only.</p> + terms:</p> + <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> + <p>The function is applied to each argument in the list. + <c>foreach</c> returns <c>ok</c>. It is only used for its + side-effect:</p> <pre> > <input>lists:foreach(fun(X) -> io:format("~w~n",[X]) end, [1,2,3,4]).</input> 1 @@ -297,15 +294,16 @@ ok</pre> <section> <title>foldl</title> - <codeinclude file="funs1.erl" tag="%8" type="erl"></codeinclude> <p><c>foldl</c> takes a function of two arguments, an - accumulator and a list. The function is called with two + accumulator and a list:</p> + <codeinclude file="funs1.erl" tag="%8" type="erl"></codeinclude> + <p>The function is called with two arguments. The first argument is the successive elements in - the list, the second argument is the accumulator. The function - must return a new accumulator which is used the next time + the list. The second argument is the accumulator. The function + must return a new accumulator, which is used the next time the function is called.</p> - <p>If we have a list of lists <c>L = ["I","like","Erlang"]</c>, - then we can sum the lengths of all the strings in <c>L</c> as + <p>If you have a list of lists <c>L = ["I","like","Erlang"]</c>, + then you can sum the lengths of all the strings in <c>L</c> as follows:</p> <pre> > <input>L = ["I","like","Erlang"].</input> @@ -325,11 +323,11 @@ end</code> <section> <title>mapfoldl</title> + <p><c>mapfoldl</c> simultaneously maps and folds over a list:</p> <codeinclude file="funs1.erl" tag="%10" type="erl"></codeinclude> - <p><c>mapfoldl</c> simultaneously maps and folds over a list. - The following example shows how to change all letters in - <c>L</c> to upper case and count them.</p> - <p>First upcase:</p> + <p>The following example shows how to change all letters in + <c>L</c> to upper case and then count them.</p> + <p>First the change to upper case:</p> <pre> > <input>Upcase = fun(X) when $a =< X, X =< $z -> X + $A - $a;</input> <input>(X) -> X</input> @@ -344,7 +342,7 @@ end</code> "ERLANG" > <input>lists:map(Upcase_word, L).</input> ["I","LIKE","ERLANG"]</pre> - <p>Now we can do the fold and the map at the same time:</p> + <p>Now, the fold and the map can be done at the same time:</p> <pre> > <input>lists:mapfoldl(fun(Word, Sum) -></input> <input>{Upcase_word(Word), Sum + length(Word)}</input> @@ -354,23 +352,24 @@ end</code> <section> <title>filter</title> - <codeinclude file="funs1.erl" tag="%9" type="erl"></codeinclude> <p><c>filter</c> takes a predicate of one argument and a list - and returns all element in the list which satisfy - the predicate.</p> + and returns all elements in the list that satisfy + the predicate:</p> + <codeinclude file="funs1.erl" tag="%9" type="erl"></codeinclude> <pre> > <input>lists:filter(Big, [500,12,2,45,6,7]).</input> [500,12,45]</pre> - <p>When we combine maps and filters we can write very succinct - code. For example, suppose we want to define a set difference - function. We want to define <c>diff(L1, L2)</c> to be - the difference between the lists <c>L1</c> and <c>L2</c>. - This is the list of all elements in L1 which are not contained - in L2. This code can be written as follows:</p> + <p>Combining maps and filters enables writing of very succinct + code. For example, to define a set difference + function <c>diff(L1, L2)</c> to be + the difference between the lists <c>L1</c> and <c>L2</c>, + the code can be written as follows:</p> <code type="none"> diff(L1, L2) -> filter(fun(X) -> not member(X, L2) end, L1).</code> - <p>The AND intersection of the list <c>L1</c> and <c>L2</c> is + <p>This gives the list of all elements in L1 that are not contained + in L2.</p> + <p> The AND intersection of the list <c>L1</c> and <c>L2</c> is also easily defined:</p> <code type="none"> intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).</code> @@ -378,9 +377,9 @@ intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).</code> <section> <title>takewhile</title> - <codeinclude file="funs1.erl" tag="%5" type="erl"></codeinclude> <p><c>takewhile(P, L)</c> takes elements <c>X</c> from a list - <c>L</c> as long as the predicate <c>P(X)</c> is true.</p> + <c>L</c> as long as the predicate <c>P(X)</c> is true:</p> + <codeinclude file="funs1.erl" tag="%5" type="erl"></codeinclude> <pre> > <input>lists:takewhile(Big, [200,500,45,5,3,45,6]).</input> [200,500,45]</pre> @@ -388,8 +387,8 @@ intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).</code> <section> <title>dropwhile</title> + <p><c>dropwhile</c> is the complement of <c>takewhile</c>:</p> <codeinclude file="funs1.erl" tag="%6" type="erl"></codeinclude> - <p><c>dropwhile</c> is the complement of <c>takewhile</c>.</p> <pre> > <input>lists:dropwhile(Big, [200,500,45,5,3,45,6]).</input> [5,3,45,6]</pre> @@ -397,10 +396,10 @@ intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).</code> <section> <title>splitwith</title> - <codeinclude file="funs1.erl" tag="%7" type="erl"></codeinclude> <p><c>splitwith(P, L)</c> splits the list <c>L</c> into the two - sub-lists <c>{L1, L2}</c>, where <c>L = takewhile(P, L)</c> - and <c>L2 = dropwhile(P, L)</c>.</p> + sublists <c>{L1, L2}</c>, where <c>L = takewhile(P, L)</c> + and <c>L2 = dropwhile(P, L)</c>:</p> + <codeinclude file="funs1.erl" tag="%7" type="erl"></codeinclude> <pre> > <input>lists:splitwith(Big, [200,500,45,5,3,45,6]).</input> {[200,500,45],[5,3,45,6]}</pre> @@ -408,17 +407,17 @@ intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).</code> </section> <section> - <title>Funs Which Return Funs</title> - <p>So far, this section has only described functions which take - funs as arguments. It is also possible to write more powerful - functions which themselves return funs. The following examples - illustrate these type of functions.</p> + <title>Funs Returning Funs</title> + <p>So far, only functions that take + funs as arguments have been described. More powerful + functions, that themselves return funs, can also be written. The following + examples illustrate these type of functions.</p> <section> <title>Simple Higher Order Functions</title> - <p><c>Adder(X)</c> is a function which, given <c>X</c>, returns + <p><c>Adder(X)</c> is a function that given <c>X</c>, returns a new function <c>G</c> such that <c>G(K)</c> returns - <c>K + X</c>.</p> + <c>K + X</c>:</p> <pre> > <input>Adder = fun(X) -> fun(Y) -> X + Y end end.</input> #Fun<erl_eval.6.72228031> @@ -438,7 +437,7 @@ ints_from(N) -> fun() -> [N|ints_from(N+1)] end.</code> - <p>Then we can proceed as follows:</p> + <p>Then proceed as follows:</p> <pre> > <input>XX = lazy:ints_from(1).</input> #Fun<lazy.0.29874839> @@ -450,7 +449,7 @@ ints_from(N) -> #Fun<lazy.0.29874839> > <input>hd(Y()).</input> 2</pre> - <p>etc. - this is an example of "lazy embedding".</p> + <p>And so on. This is an example of "lazy embedding".</p> </section> <section> @@ -459,17 +458,21 @@ ints_from(N) -> <pre> Parser(Toks) -> {ok, Tree, Toks1} | fail</pre> <p><c>Toks</c> is the list of tokens to be parsed. A successful - parse returns <c>{ok, Tree, Toks1}</c>, where <c>Tree</c> is a - parse tree and <c>Toks1</c> is a tail of <c>Tree</c> which - contains symbols encountered after the structure which was - correctly parsed. Otherwise <c>fail</c> is returned.</p> - <p>The example which follows illustrates a simple, functional - parser which parses the grammar:</p> + parse returns <c>{ok, Tree, Toks1}</c>.</p> + <list type="bulleted"> + <item><c>Tree</c> is a parse tree.</item> + <item><c>Toks1</c> is a tail of <c>Tree</c> that + contains symbols encountered after the structure that was + correctly parsed.</item> + </list> + <p>An unsuccessful parse returns <c>fail</c>.</p> + <p>The following example illustrates a simple, functional + parser that parses the grammar:</p> <pre> (a | b) & (c | d)</pre> <p>The following code defines a function <c>pconst(X)</c> in - the module <c>funparse</c>, which returns a fun which parses a - list of tokens.</p> + the module <c>funparse</c>, which returns a fun that parses a + list of tokens:</p> <codeinclude file="funparse.erl" tag="%14" type="erl"></codeinclude> <p>This function can be used as follows:</p> <pre> @@ -479,17 +482,18 @@ Parser(Toks) -> {ok, Tree, Toks1} | fail</pre> {ok,{const,a},[b,c]} > <input>P1([x,y,z]).</input> fail</pre> - <p>Next, we define the two higher order functions <c>pand</c> - and <c>por</c> which combine primitive parsers to produce more - complex parsers. Firstly <c>pand</c>:</p> + <p>Next, the two higher order functions <c>pand</c> + and <c>por</c> are defined. They combine primitive parsers to produce more + complex parsers.</p> + <p>First <c>pand</c>:</p> <codeinclude file="funparse.erl" tag="%16" type="erl"></codeinclude> <p>Given a parser <c>P1</c> for grammar <c>G1</c>, and a parser <c>P2</c> for grammar <c>G2</c>, <c>pand(P1, P2)</c> returns a - parser for the grammar which consists of sequences of tokens - which satisfy <c>G1</c> followed by sequences of tokens which + parser for the grammar, which consists of sequences of tokens + that satisfy <c>G1</c>, followed by sequences of tokens that satisfy <c>G2</c>.</p> <p><c>por(P1, P2)</c> returns a parser for the language - described by the grammar <c>G1</c> or <c>G2</c>.</p> + described by the grammar <c>G1</c> or <c>G2</c>:</p> <codeinclude file="funparse.erl" tag="%15" type="erl"></codeinclude> <p>The original problem was to parse the grammar <c><![CDATA[(a | b) & (c | d)]]></c>. The following code addresses this @@ -497,7 +501,7 @@ fail</pre> <codeinclude file="funparse.erl" tag="%13" type="erl"></codeinclude> <p>The following code adds a parser interface to the grammar:</p> <codeinclude file="funparse.erl" tag="%12" type="erl"></codeinclude> - <p>We can test this parser as follows:</p> + <p>The parser can be tested as follows:</p> <pre> > <input>funparse:parse([a,c]).</input> {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} diff --git a/system/doc/programming_examples/list_comprehensions.xml b/system/doc/programming_examples/list_comprehensions.xml index d6c8a66e13..5b33b14dea 100644 --- a/system/doc/programming_examples/list_comprehensions.xml +++ b/system/doc/programming_examples/list_comprehensions.xml @@ -31,18 +31,15 @@ <section> <title>Simple Examples</title> - <p>We start with a simple example:</p> + <p>This section starts with a simple example, showing a generator and a filter:</p> <pre> > <input>[X || X <- [1,2,a,3,4,b,5,6], X > 3].</input> [a,4,b,5,6]</pre> - <p>This should be read as follows:</p> - <quote> - <p>The list of X such that X is taken from the list + <p>This is read as follows: The list of X such that X is taken from the list <c>[1,2,a,...]</c> and X is greater than 3.</p> - </quote> <p>The notation <c><![CDATA[X <- [1,2,a,...]]]></c> is a generator and the expression <c>X > 3</c> is a filter.</p> - <p>An additional filter can be added in order to restrict + <p>An additional filter, <c>integer(X)</c>, can be added to restrict the result to integers:</p> <pre> > <input>[X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3].</input> @@ -56,7 +53,7 @@ <section> <title>Quick Sort</title> - <p>The well known quick sort routine can be written as follows:</p> + <p>The well-known quick sort routine can be written as follows:</p> <code type="none"><![CDATA[ sort([Pivot|T]) -> sort([ X || X <- T, X < Pivot]) ++ @@ -64,15 +61,20 @@ sort([Pivot|T]) -> sort([ X || X <- T, X >= Pivot]); sort([]) -> [].]]></code> <p>The expression <c><![CDATA[[X || X <- T, X < Pivot]]]></c> is the list of - all elements in <c>T</c>, which are less than <c>Pivot</c>.</p> + all elements in <c>T</c> that are less than <c>Pivot</c>.</p> <p><c><![CDATA[[X || X <- T, X >= Pivot]]]></c> is the list of all elements in - <c>T</c>, which are greater or equal to <c>Pivot</c>.</p> - <p>To sort a list, we isolate the first element in the list and - split the list into two sub-lists. The first sub-list contains - all elements which are smaller than the first element in - the list, the second contains all elements which are greater - than or equal to the first element in the list. We then sort - the sub-lists and combine the results.</p> + <c>T</c> that are greater than or equal to <c>Pivot</c>.</p> + <p>A list sorted as follows:</p> + <list type="bulleted"> + <item>The first element in the list is isolated + and the list is split into two sublists.</item> + <item>The first sublist contains + all elements that are smaller than the first element in + the list.</item> + <item>The second sublist contains all elements that are greater + than, or equal to, the first element in the list.</item> + <item>Then the sublists are sorted and the results are combined.</item> + </list> </section> <section> @@ -82,10 +84,10 @@ sort([]) -> [].]]></code> <code type="none"><![CDATA[ perms([]) -> [[]]; perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].]]></code> - <p>We take take <c>H</c> from <c>L</c> in all possible ways. + <p>This takes <c>H</c> from <c>L</c> in all possible ways. The result is the set of all lists <c>[H|T]</c>, where <c>T</c> - is the set of all possible permutations of <c>L</c> with - <c>H</c> removed.</p> + is the set of all possible permutations of <c>L</c>, with + <c>H</c> removed:</p> <pre> > <input>perms([b,u,g]).</input> [[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]]</pre> @@ -97,7 +99,7 @@ perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].]]></code> that <c>A**2 + B**2 = C**2</c>.</p> <p>The function <c>pyth(N)</c> generates a list of all integers <c>{A,B,C}</c> such that <c>A**2 + B**2 = C**2</c> and where - the sum of the sides is equal to or less than <c>N</c>.</p> + the sum of the sides is equal to, or less than, <c>N</c>:</p> <code type="none"><![CDATA[ pyth(N) -> [ {A,B,C} || @@ -140,7 +142,7 @@ pyth1(N) -> </section> <section> - <title>Simplifications with List Comprehensions</title> + <title>Simplifications With List Comprehensions</title> <p>As an example, list comprehensions can be used to simplify some of the functions in <c>lists.erl</c>:</p> <code type="none"><![CDATA[ @@ -151,45 +153,47 @@ filter(Pred, L) -> [X || X <- L, Pred(X)].]]></code> <section> <title>Variable Bindings in List Comprehensions</title> - <p>The scope rules for variables which occur in list + <p>The scope rules for variables that occur in list comprehensions are as follows:</p> <list type="bulleted"> - <item>all variables which occur in a generator pattern are - assumed to be "fresh" variables</item> - <item>any variables which are defined before the list - comprehension and which are used in filters have the values - they had before the list comprehension</item> - <item>no variables may be exported from a list comprehension.</item> + <item>All variables that occur in a generator pattern are + assumed to be "fresh" variables.</item> + <item>Any variables that are defined before the list + comprehension, and that are used in filters, have the values + they had before the list comprehension.</item> + <item>Variables cannot be exported from a list comprehension.</item> </list> - <p>As an example of these rules, suppose we want to write + <p>As an example of these rules, suppose you want to write the function <c>select</c>, which selects certain elements from - a list of tuples. We might write + a list of tuples. Suppose you write <c><![CDATA[select(X, L) -> [Y || {X, Y} <- L].]]></c> with the intention - of extracting all tuples from <c>L</c> where the first item is + of extracting all tuples from <c>L</c>, where the first item is <c>X</c>.</p> - <p>Compiling this yields the following diagnostic:</p> + <p>Compiling this gives the following diagnostic:</p> <code type="none"> ./FileName.erl:Line: Warning: variable 'X' shadowed in generate</code> - <p>This diagnostic warns us that the variable <c>X</c> in - the pattern is not the same variable as the variable <c>X</c> - which occurs in the function head.</p> - <p>Evaluating <c>select</c> yields the following result:</p> + <p>This diagnostic warns that the variable <c>X</c> in + the pattern is not the same as the variable <c>X</c> + that occurs in the function head.</p> + <p>Evaluating <c>select</c> gives the following result:</p> <pre> > <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> [1,2,3,7]</pre> - <p>This result is not what we wanted. To achieve the desired - effect we must write <c>select</c> as follows:</p> + <p>This is not the wanted result. To achieve the desired + effect, <c>select</c> must be written as follows:</p> <code type="none"><![CDATA[ select(X, L) -> [Y || {X1, Y} <- L, X == X1].]]></code> <p>The generator now contains unbound variables and the test has - been moved into the filter. This now works as expected:</p> + been moved into the filter.</p> + <p>This now works as expected:</p> <pre> > <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> [2,7]</pre> - <p>One consequence of the rules for importing variables into a + <p>A consequence of the rules for importing variables into a list comprehensions is that certain pattern matching operations - have to be moved into the filters and cannot be written directly - in the generators. To illustrate this, do not write as follows:</p> + must be moved into the filters and cannot be written directly + in the generators.</p> + <p>To illustrate this, do <em>not</em> write as follows:</p> <code type="none"><![CDATA[ f(...) -> Y = ... diff --git a/system/doc/programming_examples/part.xml b/system/doc/programming_examples/part.xml index 0bec9b4cf5..9329717ce4 100644 --- a/system/doc/programming_examples/part.xml +++ b/system/doc/programming_examples/part.xml @@ -28,8 +28,9 @@ <rev></rev> </header> <description> - <p>This chapter contains examples on using records, funs, list - comprehensions and the bit syntax.</p> + <marker id="programming examples"></marker> + <p>This section contains examples on using records, funs, list + comprehensions, and the bit syntax.</p> </description> <xi:include href="records.xml"/> <xi:include href="funs.xml"/> diff --git a/system/doc/programming_examples/records.xml b/system/doc/programming_examples/records.xml index 58cf136a0b..ffcc05e758 100644 --- a/system/doc/programming_examples/records.xml +++ b/system/doc/programming_examples/records.xml @@ -30,37 +30,39 @@ </header> <section> - <title>Records vs Tuples</title> - <p>The main advantage of using records instead of tuples is that + <title>Records and Tuples</title> + <p>The main advantage of using records rather than tuples is that fields in a record are accessed by name, whereas fields in a tuple are accessed by position. To illustrate these differences, - suppose that we want to represent a person with the tuple + suppose that you want to represent a person with the tuple <c>{Name, Address, Phone}</c>.</p> - <p>We must remember that the <c>Name</c> field is the first - element of the tuple, the <c>Address</c> field is the second - element, and so on, in order to write functions which manipulate - this data. For example, to extract data from a variable <c>P</c> - which contains such a tuple we might write the following code - and then use pattern matching to extract the relevant fields.</p> + <p>To write functions that manipulate this data, remember the following:</p> + <list type="bulleted"> + <item>The <c>Name</c> field is the first element of the tuple.</item> + <item>The <c>Address</c> field is the second element.</item> + <item>The <c>Phone</c> field is the third element.</item> + </list> + <p>For example, to extract data from a variable <c>P</c> + that contains such a tuple, you can write the following code + and then use pattern matching to extract the relevant fields:</p> <code type="none"> Name = element(1, P), Address = element(2, P), ...</code> - <p>Code like this is difficult to read and understand and errors - occur if we get the numbering of the elements in the tuple wrong. - If we change the data representation by re-ordering the fields, - or by adding or removing a field, then all references to - the person tuple, wherever they occur, must be checked and - possibly modified.</p> - <p>Records allow us to refer to the fields by name and not - position. We use a record instead of a tuple to store the data. - If we write a record definition of the type shown below, we can - then refer to the fields of the record by name.</p> + <p>Such code is difficult to read and understand, and errors + occur if the numbering of the elements in the tuple is wrong. + If the data representation of the fields is changed, by re-ordering, + adding, or removing fields, all references to + the person tuple must be checked and possibly modified.</p> + <p>Records allow references to the fields by name, instead of by + position. In the following example, a record instead of a tuple + is used to store the data:</p> <code type="none"> -record(person, {name, phone, address}).</code> - <p>For example, if <c>P</c> is now a variable whose value is a - <c>person</c> record, we can code as follows in order to access - the name and address fields of the records.</p> + <p>This enables references to the fields of the record by name. + For example, if <c>P</c> is a variable whose value is a + <c>person</c> record, the following code access + the name and address fields of the records:</p> <code type="none"> Name = P#person.name, Address = P#person.address, @@ -72,24 +74,25 @@ Address = P#person.address, <section> <title>Defining a Record</title> - <p>This definition of a person will be used in many of - the examples which follow. It contains three fields, <c>name</c>, - <c>phone</c> and <c>address</c>. The default values for + <p>This following definition of a <c>person</c> is used in several + examples in this section. Three fields are included, <c>name</c>, + <c>phone</c>, and <c>address</c>. The default values for <c>name</c> and <c>phone</c> is "" and [], respectively. The default value for <c>address</c> is the atom <c>undefined</c>, since no default value is supplied for this field:</p> <pre> -record(person, {name = "", phone = [], address}).</pre> - <p>We have to define the record in the shell in order to be able - use the record syntax in the examples:</p> + <p>The record must be defined in the shell to enable + use of the record syntax in the examples:</p> <pre> > <input>rd(person, {name = "", phone = [], address}).</input> person</pre> - <p>This is due to the fact that record definitions are available - at compile time only, not at runtime. See <c>shell(3)</c> for - details on records in the shell. - </p> + <p>This is because record definitions are only available + at compile time, not at runtime. For details on records + in the shell, see the + <seealso marker="stdlib:shell">shell(3)</seealso> + manual page in <c>stdlib</c>.</p> </section> <section> @@ -98,12 +101,12 @@ person</pre> <pre> > <input>#person{phone=[0,8,2,3,4,3,1,2], name="Robert"}.</input> #person{name = "Robert",phone = [0,8,2,3,4,3,1,2],address = undefined}</pre> - <p>Since the <c>address</c> field was omitted, its default value + <p>As the <c>address</c> field was omitted, its default value is used.</p> - <p>There is a new feature introduced in Erlang 5.1/OTP R8B, - with which you can set a value to all fields in a record, - overriding the defaults in the record specification. The special - field <c>_</c>, means "all fields not explicitly specified".</p> + <p>From Erlang 5.1/OTP R8B, a value to all + fields in a record can be set with the special field <c>_</c>. + <c>_</c> means "all fields not explicitly specified".</p> + <p><em>Example:</em></p> <pre> > <input>#person{name = "Jakob", _ = '_'}.</input> #person{name = "Jakob",phone = '_',address = '_'}</pre> @@ -114,6 +117,7 @@ person</pre> <section> <title>Accessing a Record Field</title> + <p>The following example shows how to access a record field:</p> <pre> > <input>P = #person{name = "Joe", phone = [0,8,2,3,4,3,1,2]}.</input> #person{name = "Joe",phone = [0,8,2,3,4,3,1,2],address = undefined} @@ -123,6 +127,7 @@ person</pre> <section> <title>Updating a Record</title> + <p>The following example shows how to update a record:</p> <pre> > <input>P1 = #person{name="Joe", phone=[1,2,3], address="A street"}.</input> #person{name = "Joe",phone = [1,2,3],address = "A street"} @@ -133,7 +138,7 @@ person</pre> <section> <title>Type Testing</title> <p>The following example shows that the guard succeeds if - <c>P</c> is record of type <c>person</c>.</p> + <c>P</c> is record of type <c>person</c>:</p> <pre> foo(P) when is_record(P, person) -> a_person; foo(_) -> not_a_person.</pre> @@ -141,7 +146,7 @@ foo(_) -> not_a_person.</pre> <section> <title>Pattern Matching</title> - <p>Matching can be used in combination with records as shown in + <p>Matching can be used in combination with records, as shown in the following example:</p> <pre> > <input>P3 = #person{name="Joe", phone=[0,0,7], address="A street"}.</input> @@ -163,7 +168,7 @@ find_phone([], Name) -> <section> <title>Nested Records</title> - <p>The value of a field in a record might be an instance of a + <p>The value of a field in a record can be an instance of a record. Retrieval of nested data can be done stepwise, or in a single step, as shown in the following example:</p> <pre> @@ -173,11 +178,12 @@ find_phone([], Name) -> demo() -> P = #person{name= #name{first="Robert",last="Virding"}, phone=123}, First = (P#person.name)#name.first.</pre> - <p>In this example, <c>demo()</c> evaluates to <c>"Robert"</c>.</p> + <p>Here, <c>demo()</c> evaluates to <c>"Robert"</c>.</p> </section> <section> - <title>Example</title> + <title>A Longer Example</title> + <p>Comments are embedded in the following example:</p> <pre> %% File: person.hrl |