diff options
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 | 280 | ||||
-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, 349 insertions, 320 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..e4f5c9c9c9 100644 --- a/system/doc/programming_examples/funs.xmlsrc +++ b/system/doc/programming_examples/funs.xmlsrc @@ -30,128 +30,124 @@ </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> <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 @@ -161,15 +157,15 @@ f(N, _) when is_integer(N) -> <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 +173,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 +187,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 + <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 +213,7 @@ f(...) -> ... end, ...) ...</code> - <p>instead of</p> + <p>instead of writng the following code:</p> <code type="none"> f(...) -> Y = ... @@ -229,35 +226,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 +268,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 +281,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 +298,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 +327,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 +346,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 +356,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 +381,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 +391,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 +400,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 +411,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 +441,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 +453,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 +462,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 +486,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 +505,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 |