aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/programming_examples
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/programming_examples')
-rw-r--r--system/doc/programming_examples/Makefile98
-rw-r--r--system/doc/programming_examples/bit_syntax.xml327
-rw-r--r--system/doc/programming_examples/book.xml37
-rw-r--r--system/doc/programming_examples/fun_test.erl17
-rw-r--r--system/doc/programming_examples/funparse.erl74
-rw-r--r--system/doc/programming_examples/funs.xmlsrc515
-rw-r--r--system/doc/programming_examples/funs1.erl125
-rw-r--r--system/doc/programming_examples/list_comprehensions.xml206
-rw-r--r--system/doc/programming_examples/make.dep20
-rw-r--r--system/doc/programming_examples/part.xml39
-rw-r--r--system/doc/programming_examples/records.xml232
-rw-r--r--system/doc/programming_examples/xmlfiles.mk23
12 files changed, 1713 insertions, 0 deletions
diff --git a/system/doc/programming_examples/Makefile b/system/doc/programming_examples/Makefile
new file mode 100644
index 0000000000..73512c9654
--- /dev/null
+++ b/system/doc/programming_examples/Makefile
@@ -0,0 +1,98 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include $(ERL_TOP)/erts/vsn.mk
+#VSN=$(SYSTEM_VSN)
+
+APPLICATION=otp-system-documentation
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/doc/programming_examples
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+XML_PART_FILES = part.xml
+
+include xmlfiles.mk
+
+XML_CHAPTER_FILES=$(PROG_EX_CHAPTER_FILES)
+
+TOPDOCDIR=..
+
+BOOK_FILES = book.xml
+
+GIF_FILES =
+
+PS_FILES =
+
+XML_FILES = \
+ $(BOOK_FILES) $(XML_CHAPTER_FILES) \
+ $(XML_PART_FILES)
+# ----------------------------------------------------
+
+HTML_FILES = \
+ $(XML_PART_FILES:%.xml=%.html)
+
+HTMLDIR = ../html/programming_examples
+
+HTML_UG_FILE = $(HTMLDIR)/users_guide.html
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+DVIPS_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+docs: html
+local_docs: PDFDIR=../../pdf
+
+html: $(GIF_FILES) $(HTML_UG_FILE)
+
+debug opt:
+
+clean clean_docs:
+ rm -rf $(HTMLDIR)
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f errs core *~
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_docs_spec: docs
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \
+ $(RELSYSDIR)
+
+release_spec:
+
+
+
diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml
new file mode 100644
index 0000000000..3306365c0e
--- /dev/null
+++ b/system/doc/programming_examples/bit_syntax.xml
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Bit Syntax</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>bit_syntax.xml</file>
+ </header>
+
+ <section>
+ <title>Introduction</title>
+ <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>
+ <code type="none"><![CDATA[
+Bin = <<E1, E2, ... En>>]]></code>
+ <p>in which case all elements must be bound, or to 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
+ unbound, as in any match.</p>
+ <p>In R12B, a Bin need not 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
+ 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
+ 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
+ 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
+ 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
+ specify a 16-bits segment of <c>Bin2</c>.</p>
+ <p><em>Example 3: </em>A Bin can also be used for matching: if
+ <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>
+ <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
+ 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>
+ <code type="none"><![CDATA[
+-define(IP_VERSION, 4).
+-define(IP_MIN_HDR_LEN, 5).
+
+DgramSize = byte_size(Dgram),
+case Dgram of
+ <<?IP_VERSION:4, HLen:4, SrvcType:8, TotLen:16,
+ ID:16, Flgs:3, FragOff:13,
+ TTL:8, Proto:8, HdrChkSum:16,
+ SrcIP:32,
+ DestIP:32, RestDgram/binary>> when HLen>=5, 4*HLen=<DgramSize ->
+ OptsLen = 4*(HLen - ?IP_MIN_HDR_LEN),
+ <<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
+ 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>The tail variables <c>RestDgram</c> and <c>Data</c> bind to
+ binaries, as all tail variables do. Both may 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>
+ </section>
+ </section>
+
+ <section>
+ <title>A Lexical Note</title>
+ <p>Note 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>
+ </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
+ <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>Size</c> part of the segment multiplied by the unit in
+ the <c>TypeSpecifierList</c> (described below) 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>
+ <p>The <c>TypeSpecifierList</c> is a list of type specifiers
+ separated by hyphens.</p>
+ <taglist>
+ <tag>Type</tag>
+ <item>The type can be <c>integer</c>, <c>float</c>, or
+ <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
+ 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
+ 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 <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>
+ </taglist>
+ <p>Example:</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
+ a signed integer in little-endian order.</p>
+ </section>
+
+ <section>
+ <title>Defaults</title>
+ <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
+ 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
+ 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>,
+ <c>float</c>, and <c>bitstring</c> it is 1. For binary it is 8.</p>
+ <p>The default signedness is <c>unsigned</c>.</p>
+ <p>The default endianness is <c>big</c>.</p>
+ </section>
+
+ <section>
+ <title>Constructing Binaries and Bitstrings</title>
+ <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
+ 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>
+ <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>
+
+ <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>
+
+ <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>The following example</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><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>
+ <code type="none"><![CDATA[
+<<X+1:8>>]]></code>
+ <p>This expression must be rewritten to</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>
+ <code type="none"><![CDATA[
+<<"hello">>]]></code>
+ <p>which is syntactic sugar for</p>
+ <code type="none"><![CDATA[
+<<$h,$e,$l,$l,$o>>]]></code>
+ </section>
+ </section>
+
+ <section>
+ <title>Matching Binaries</title>
+ <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>
+ <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
+ allowed.</p>
+ <p><c>Size</c> must be an integer literal, or a previously bound
+ variable. Note that 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>
+ <code type="none"><![CDATA[
+foo(N, Bin) ->
+ <<X:N,T/binary>> = Bin,
+ {X,T}.]]></code>
+
+ <section>
+ <title>Getting the Rest of the Binary or Bitstring</title>
+ <p>To match out the rest of a binary, specify a binary field
+ without size:</p>
+ <code type="none"><![CDATA[
+foo(<<A:8,Rest/binary>>) ->]]></code>
+ <p>The size of the tail must be evenly divisible by 8.</p>
+
+ <p>To match out the rest of a bitstring, specify a field
+ 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>
+ </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>
+ <code type="none"><![CDATA[
+triples_to_bin(T) ->
+ triples_to_bin(T, <<>>).
+
+triples_to_bin([{X,Y,Z} | T], Acc) ->
+ triples_to_bin(T, <<Acc/binary,X:32,Y:32,Z:32>>); % inefficient before R12B
+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>
+ </section>
+</chapter>
+
diff --git a/system/doc/programming_examples/book.xml b/system/doc/programming_examples/book.xml
new file mode 100644
index 0000000000..91346ceea4
--- /dev/null
+++ b/system/doc/programming_examples/book.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Programming Examples</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <pagetext>Programming Examples</pagetext>
+ <preamble>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="part.xml"/>
+ </parts>
+</book>
+
diff --git a/system/doc/programming_examples/fun_test.erl b/system/doc/programming_examples/fun_test.erl
new file mode 100644
index 0000000000..8472fd87f8
--- /dev/null
+++ b/system/doc/programming_examples/fun_test.erl
@@ -0,0 +1,17 @@
+%1
+-module(fun_test).
+-export([t1/0, t2/0, t3/0, t4/0, double/1]).
+-import(lists, [map/2]).
+
+t1() -> map(fun(X) -> 2 * X end, [1,2,3,4,5]).
+
+t2() -> map(fun double/1, [1,2,3,4,5]).
+
+t3() -> map({?MODULE, double}, [1,2,3,4,5]).
+
+double(X) -> X * 2.
+%1
+
+
+t4() ->
+ "hello world".
diff --git a/system/doc/programming_examples/funparse.erl b/system/doc/programming_examples/funparse.erl
new file mode 100644
index 0000000000..5e23c90df9
--- /dev/null
+++ b/system/doc/programming_examples/funparse.erl
@@ -0,0 +1,74 @@
+-module(funparse).
+-compile(export_all).
+-import(lists, [reverse/1]).
+
+%17
+%% > hof:parse([a,c]).
+%% {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}}
+%% > hof:parse([a,d]).
+%% {ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}}
+%% > hof:parse([b,c]).
+%% {ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}}
+%% > hof:parse([b,d]).
+%% {ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}}
+%% > hof:parse([a,b]).
+%% fail
+%17
+
+%% Grammar = (a | b) & (c | d)
+
+%12
+parse(List) ->
+ (grammar())(List).
+%12
+
+%13
+grammar() ->
+ pand(
+ por(pconst(a), pconst(b)),
+ por(pconst(c), pconst(d))).
+%13
+
+%14
+pconst(X) ->
+ fun (T) ->
+ case T of
+ [X|T1] -> {ok, {const, X}, T1};
+ _ -> fail
+ end
+ end.
+%14
+
+%15
+por(P1, P2) ->
+ fun (T) ->
+ case P1(T) of
+ {ok, R, T1} ->
+ {ok, {'or',1,R}, T1};
+ fail ->
+ case P2(T) of
+ {ok, R1, T1} ->
+ {ok, {'or',2,R1}, T1};
+ fail ->
+ fail
+ end
+ end
+ end.
+%15
+
+%16
+pand(P1, P2) ->
+ fun (T) ->
+ case P1(T) of
+ {ok, R1, T1} ->
+ case P2(T1) of
+ {ok, R2, T2} ->
+ {ok, {'and', R1, R2}};
+ fail ->
+ fail
+ end;
+ fail ->
+ fail
+ end
+ end.
+%16
diff --git a/system/doc/programming_examples/funs.xmlsrc b/system/doc/programming_examples/funs.xmlsrc
new file mode 100644
index 0000000000..92f99cf6d3
--- /dev/null
+++ b/system/doc/programming_examples/funs.xmlsrc
@@ -0,0 +1,515 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Funs</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>funs.xml</file>
+ </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>
+ <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>
+ <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
+ 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>
+ <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>
+ <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
+ 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>
+ <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
+ 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>
+ <code type="none">
+print_list(Stream, [H|T]) ->
+ io:format(Stream, "~p~n", [H]),
+ print_list(Stream, T);
+print_list(Stream, []) ->
+ true.</code>
+ <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>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>
+ <code type="none">
+foreach(fun(H) -> io:format(S, "~p~n",[H]) end, L)</code>
+ <p><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>.
+ <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>
+ <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>
+ <code type="none">
+F = fun FunctionName/Arity</code>
+ <p>With this form of function reference, the function which 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
+ 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
+ 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>
+ <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>
+ <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
+ 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
+ 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
+ follows:</p>
+ <list type="bulleted">
+ <item>All variables which occur in the head of a fun are assumed
+ to be "fresh" variables.</item>
+ <item>Variables which are defined before the fun, and which
+ 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>
+ </list>
+ <p>The following examples illustrate these rules:</p>
+ <code type="none">
+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
+ 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>
+ <code type="none">
+print_list(File, List) ->
+ {ok, Stream} = file:open(File, write),
+ foreach(fun(File) ->
+ 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>
+ <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
+ 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
+ guard expressions and cannot be written in the head of the fun.
+ For example, we might write the following code if we 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">
+f(...) ->
+ Y = ...
+ map(fun(X) when X == Y ->
+ ;
+ (_) ->
+ ...
+ end, ...)
+ ...</code>
+ <p>instead of</p>
+ <code type="none">
+f(...) ->
+ Y = ...
+ map(fun(Y) ->
+ ;
+ (_) ->
+ ...
+ end, ...)
+ ...</code>
+ </section>
+
+ <section>
+ <title>Funs and the 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>
+ <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
+ to every argument in the list.</p>
+ <pre>
+> <input>Double = fun(X) -> 2 * X end.</input>
+#Fun&lt;erl_eval.6.72228031&gt;
+> <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>
+ <pre>
+> <input>Big = fun(X) -> if X > 10 -> true; true -> false end end.</input>
+#Fun&lt;erl_eval.6.72228031&gt;
+> <input>lists:any(Big, [1,2,3,4]).</input>
+false
+> <input>lists:any(Big, [1,2,3,12,5]).</input>
+true</pre>
+ </section>
+
+ <section>
+ <title>all</title>
+ <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>
+ <pre>
+> <input>lists:all(Big, [1,2,3,4,12,6]).</input>
+false
+> <input>lists:all(Big, [12,13,14,15]).</input>
+true</pre>
+ </section>
+
+ <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>
+ <pre>
+> <input>lists:foreach(fun(X) -> io:format("~w~n",[X]) end, [1,2,3,4]).</input>
+1
+2
+3
+4
+ok</pre>
+ </section>
+
+ <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
+ 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 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
+ follows:</p>
+ <pre>
+> <input>L = ["I","like","Erlang"].</input>
+["I","like","Erlang"]
+10> <input>lists:foldl(fun(X, Sum) -> length(X) + Sum end, 0, L).</input>
+11</pre>
+ <p><c>foldl</c> works like a <c>while</c> loop in an imperative
+ language:</p>
+ <code type="none">
+L = ["I","like","Erlang"],
+Sum = 0,
+while( L != []){
+ Sum += length(head(L)),
+ L = tail(L)
+end</code>
+ </section>
+
+ <section>
+ <title>mapfoldl</title>
+ <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>
+ <pre>
+> <input>Upcase = fun(X) when $a =&lt; X, X =&lt; $z -> X + $A - $a;</input>
+<input>(X) -> X</input>
+<input>end.</input>
+#Fun&lt;erl_eval.6.72228031&gt;
+> <input>Upcase_word =</input>
+<input>fun(X) -></input>
+<input>lists:map(Upcase, X)</input>
+<input>end.</input>
+#Fun&lt;erl_eval.6.72228031&gt;
+> <input>Upcase_word("Erlang").</input>
+"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>
+ <pre>
+> <input>lists:mapfoldl(fun(Word, Sum) -></input>
+<input>{Upcase_word(Word), Sum + length(Word)}</input>
+<input>end, 0, L).</input>
+{["I","LIKE","ERLANG"],11}</pre>
+ </section>
+
+ <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>
+ <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>
+ <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
+ also easily defined:</p>
+ <code type="none">
+intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).</code>
+ </section>
+
+ <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>
+ <pre>
+> <input>lists:takewhile(Big, [200,500,45,5,3,45,6]).</input>
+[200,500,45]</pre>
+ </section>
+
+ <section>
+ <title>dropwhile</title>
+ <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>
+ </section>
+
+ <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>
+ <pre>
+> <input>lists:splitwith(Big, [200,500,45,5,3,45,6]).</input>
+{[200,500,45],[5,3,45,6]}</pre>
+ </section>
+ </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>
+
+ <section>
+ <title>Simple Higher Order Functions</title>
+ <p><c>Adder(X)</c> is a function which, given <c>X</c>, returns
+ a new function <c>G</c> such that <c>G(K)</c> returns
+ <c>K + X</c>.</p>
+ <pre>
+> <input>Adder = fun(X) -> fun(Y) -> X + Y end end.</input>
+#Fun&lt;erl_eval.6.72228031&gt;
+> <input>Add6 = Adder(6).</input>
+#Fun&lt;erl_eval.6.72228031&gt;
+> <input>Add6(10).</input>
+16</pre>
+ </section>
+
+ <section>
+ <title>Infinite Lists</title>
+ <p>The idea is to write something like:</p>
+ <code type="none">
+-module(lazy).
+-export([ints_from/1]).
+ints_from(N) ->
+ fun() ->
+ [N|ints_from(N+1)]
+ end.</code>
+ <p>Then we can proceed as follows:</p>
+ <pre>
+> <input>XX = lazy:ints_from(1).</input>
+#Fun&lt;lazy.0.29874839&gt;
+> <input>XX().</input>
+[1|#Fun&lt;lazy.0.29874839&gt;]
+> <input>hd(XX()).</input>
+1
+> <input>Y = tl(XX()).</input>
+#Fun&lt;lazy.0.29874839&gt;
+> <input>hd(Y()).</input>
+2</pre>
+ <p>etc. - this is an example of "lazy embedding".</p>
+ </section>
+
+ <section>
+ <title>Parsing</title>
+ <p>The following examples show parsers of the following type:</p>
+ <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>
+ <pre>
+(a | b) &amp; (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>
+ <codeinclude file="funparse.erl" tag="%14" type="erl"></codeinclude>
+ <p>This function can be used as follows:</p>
+ <pre>
+> <input>P1 = funparse:pconst(a).</input>
+#Fun&lt;funparse.0.22674075&gt;
+> <input>P1([a,b,c]).</input>
+{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>
+ <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
+ 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>
+ <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
+ problem:</p>
+ <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>
+ <pre>
+> <input>funparse:parse([a,c]).</input>
+{ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}}
+> <input>funparse:parse([a,d]).</input>
+{ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}}
+> <input>funparse:parse([b,c]).</input>
+{ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}}
+> <input>funparse:parse([b,d]).</input>
+{ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}}
+> <input>funparse:parse([a,b]).</input>
+fail</pre>
+ </section>
+ </section>
+</chapter>
+
diff --git a/system/doc/programming_examples/funs1.erl b/system/doc/programming_examples/funs1.erl
new file mode 100644
index 0000000000..8cf20378ea
--- /dev/null
+++ b/system/doc/programming_examples/funs1.erl
@@ -0,0 +1,125 @@
+-module(funs1).
+-compile(export_all).
+-import(lists, [reverse/1]).
+
+%1
+map(F, [H|T]) -> [F(H)|map(F, T)];
+map(F, []) -> [].
+%1
+
+%2
+foreach(F, [H|T]) ->
+ F(H),
+ foreach(F, T);
+foreach(F, []) ->
+ ok.
+%2
+%
+%3
+all(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> all(Pred, T);
+ false -> false
+ end;
+all(Pred, []) ->
+ true.
+%3
+%4
+any(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> true;
+ false -> any(Pred, T)
+ end;
+any(Pred, []) ->
+ false.
+%4
+%5
+takewhile(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> [H|takewhile(Pred, T)];
+ false -> []
+ end;
+takewhile(Pred, []) ->
+ [].
+%5
+%6
+dropwhile(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> dropwhile(Pred, T);
+ false -> [H|T]
+ end;
+dropwhile(Pred, []) ->
+ [].
+%6
+%7
+splitwith(Pred, L) ->
+ splitwith(Pred, L, []).
+
+splitwith(Pred, [H|T], L) ->
+ case Pred(H) of
+ true -> splitwith(Pred, T, [H|L]);
+ false -> {reverse(L), [H|T]}
+ end;
+splitwith(Pred, [], L) ->
+ {reverse(L), []}.
+%7
+
+flatmap(F, [Hd|Tail]) ->
+ F(Hd) ++ flatmap(F, Tail);
+flatmap(F, []) -> [].
+
+%8
+foldl(F, Accu, [Hd|Tail]) ->
+ foldl(F, F(Hd, Accu), Tail);
+foldl(F, Accu, []) -> Accu.
+%8
+%
+foldr(F, Accu, [Hd|Tail]) ->
+ F(Hd, foldr(F, Accu, Tail));
+foldr(F, Accu, []) -> Accu.
+%9
+filter(F, [H|T]) ->
+ case F(H) of
+ true -> [H|filter(F, T)];
+ false -> filter(F, T)
+ end;
+filter(F, []) -> [].
+%9
+%10
+mapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = mapfoldl(F, Accu1, Tail),
+ {[R|Rs], Accu2};
+mapfoldl(F, Accu, []) -> {[], Accu}.
+%10
+mapfoldr(F, Accu0, [Hd|Tail]) ->
+ {Rs,Accu1} = mapfoldr(F, Accu0, Tail),
+ {R,Accu2} = F(Hd, Accu1),
+ {[R|Rs],Accu2};
+mapfoldr(F, Accu, []) -> {[], Accu}.
+%11
+first(Pred, [H|T]) ->
+ case Pred(H) of
+ true ->
+ {true, H};
+ false ->
+ first(Pred, T)
+ end;
+first(Pred, []) ->
+ false.
+%11
+%
+compose(F, G) ->
+ fun(X) ->
+ F(G(X))
+ end.
+
+%20
+iterate(N, F) ->
+ iterate(N, N+1, F).
+
+iterate(Stop, Stop, _) ->
+ [];
+iterate(N, Stop, Fun) ->
+ [Fun(N)|iterate(N+1, Stop, Fun)].
+%20
diff --git a/system/doc/programming_examples/list_comprehensions.xml b/system/doc/programming_examples/list_comprehensions.xml
new file mode 100644
index 0000000000..825459238b
--- /dev/null
+++ b/system/doc/programming_examples/list_comprehensions.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>List Comprehensions</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>list_comprehensions.xml</file>
+ </header>
+
+ <section>
+ <title>Simple Examples</title>
+ <p>We start with a simple example:</p>
+ <pre>
+> <input>[X || X &lt;- [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
+ <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
+ the result to integers:</p>
+ <pre>
+> <input>[X || X &lt;- [1,2,a,3,4,b,5,6], integer(X), X > 3].</input>
+[4,5,6]</pre>
+ <p>Generators can be combined. For example, the Cartesian product
+ of two lists can be written as follows:</p>
+ <pre>
+> <input>[{X, Y} || X &lt;- [1,2,3], Y &lt;- [a,b]].</input>
+[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}]</pre>
+ </section>
+
+ <section>
+ <title>Quick Sort</title>
+ <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]) ++
+ [Pivot] ++
+ 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>
+ <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>
+ </section>
+
+ <section>
+ <title>Permutations</title>
+ <p>The following example generates all permutations of
+ the elements in a list:</p>
+ <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.
+ 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>
+ <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>
+ </section>
+
+ <section>
+ <title>Pythagorean Triplets</title>
+ <p>Pythagorean triplets are sets of integers <c>{A,B,C}</c> such
+ 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>
+ <code type="none"><![CDATA[
+pyth(N) ->
+ [ {A,B,C} ||
+ A <- lists:seq(1,N),
+ B <- lists:seq(1,N),
+ C <- lists:seq(1,N),
+ A+B+C =< N,
+ A*A+B*B == C*C
+ ].]]></code>
+ <pre>
+> <input>pyth(3).</input>
+[].
+> <input>pyth(11).</input>
+[].
+> <input>pyth(12).</input>
+[{3,4,5},{4,3,5}]
+> <input>pyth(50).</input>
+[{3,4,5},
+ {4,3,5},
+ {5,12,13},
+ {6,8,10},
+ {8,6,10},
+ {8,15,17},
+ {9,12,15},
+ {12,5,13},
+ {12,9,15},
+ {12,16,20},
+ {15,8,17},
+ {16,12,20}]</pre>
+ <p>The following code reduces the search space and is more
+ efficient:</p>
+ <code type="none"><![CDATA[
+pyth1(N) ->
+ [{A,B,C} ||
+ A <- lists:seq(1,N-2),
+ B <- lists:seq(A+1,N-1),
+ C <- lists:seq(B+1,N),
+ A+B+C =< N,
+ A*A+B*B == C*C ].]]></code>
+ </section>
+
+ <section>
+ <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[
+append(L) -> [X || L1 <- L, X <- L1].
+map(Fun, L) -> [Fun(X) || X <- L].
+filter(Pred, L) -> [X || X <- L, Pred(X)].]]></code>
+ </section>
+
+ <section>
+ <title>Variable Bindings in List Comprehensions</title>
+ <p>The scope rules for variables which 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>
+ </list>
+ <p>As an example of these rules, suppose we want to write
+ the function <c>select</c>, which selects certain elements from
+ a list of tuples. We might 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
+ <c>X</c>.</p>
+ <p>Compiling this yields 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>
+ <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>
+ <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>
+ <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
+ 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>
+ <code type="none"><![CDATA[
+f(...) ->
+ Y = ...
+ [ Expression || PatternInvolving Y <- Expr, ...]
+ ...]]></code>
+ <p>Instead, write as follows:</p>
+ <code type="none"><![CDATA[
+f(...) ->
+ Y = ...
+ [ Expression || PatternInvolving Y1 <- Expr, Y == Y1, ...]
+ ...]]></code>
+ </section>
+</chapter>
+
diff --git a/system/doc/programming_examples/make.dep b/system/doc/programming_examples/make.dep
new file mode 100644
index 0000000000..b0655f56b3
--- /dev/null
+++ b/system/doc/programming_examples/make.dep
@@ -0,0 +1,20 @@
+# ----------------------------------------------------
+# >>>> Do not edit this file <<<<
+# This file was automaticly generated by
+# /home/otp/bin/docdepend
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# TeX files that the DVI file depend on
+# ----------------------------------------------------
+
+book.dvi: bit_syntax.tex book.tex funs.tex list_comprehensions.tex \
+ part.tex records.tex
+
+# ----------------------------------------------------
+# Source inlined when transforming from source to LaTeX
+# ----------------------------------------------------
+
+funs.tex: fun_test.erl funparse.erl funs1.erl
+
diff --git a/system/doc/programming_examples/part.xml b/system/doc/programming_examples/part.xml
new file mode 100644
index 0000000000..5b22ddf82f
--- /dev/null
+++ b/system/doc/programming_examples/part.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Programming Examples</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <description>
+ <p>This chapter contains examples on using records, funs, list
+ comprehensions and the bit syntax.</p>
+ </description>
+ <xi:include href="records.xml"/>
+ <xi:include href="funs.xml"/>
+ <xi:include href="list_comprehensions.xml"/>
+ <xi:include href="bit_syntax.xml"/>
+</part>
+
diff --git a/system/doc/programming_examples/records.xml b/system/doc/programming_examples/records.xml
new file mode 100644
index 0000000000..2f2434f11c
--- /dev/null
+++ b/system/doc/programming_examples/records.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Records</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>records.xml</file>
+ </header>
+
+ <section>
+ <title>Records vs Tuples</title>
+ <p>The main advantage of using records instead of 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
+ <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>
+ <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>
+ <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>
+ <code type="none">
+Name = P#person.name,
+Address = P#person.address,
+...</code>
+ <p>Internally, records are represented using tagged tuples:</p>
+ <code type="none">
+{person, Name, Phone, Address}</code>
+ </section>
+
+ <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
+ <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>
+ <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>
+ </section>
+
+ <section>
+ <title>Creating a Record</title>
+ <p>A new <c>person</c> record is created as follows:</p>
+ <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
+ 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>
+ <pre>
+> <input>#person{name = "Jakob", _ = '_'}.</input>
+#person{name = "Jakob",phone = '_',address = '_'}</pre>
+ <p>It is primarily intended to be used in <c>ets:match/2</c> and
+ <c>mnesia:match_object/3</c>, to set record fields to the atom
+ <c>'_'</c>. (This is a wildcard in <c>ets:match/2</c>.)</p>
+ </section>
+
+ <section>
+ <title>Accessing a Record Field</title>
+ <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}
+> <input>P#person.name.</input>
+"Joe"</pre>
+ </section>
+
+ <section>
+ <title>Updating a Record</title>
+ <pre>
+> <input>P1 = #person{name="Joe", phone=[1,2,3], address="A street"}.</input>
+#person{name = "Joe",phone = [1,2,3],address = "A street"}
+> <input>P2 = P1#person{name="Robert"}.</input>
+#person{name = "Robert",phone = [1,2,3],address = "A street"}</pre>
+ </section>
+
+ <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>
+ <pre>
+foo(P) when is_record(P, person) -> a_person;
+foo(_) -> not_a_person.</pre>
+ </section>
+
+ <section>
+ <title>Pattern Matching</title>
+ <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>
+#person{name = "Joe",phone = [0,0,7],address = "A street"}
+> <input>#person{name = Name} = P3, Name.</input>
+"Joe"</pre>
+ <p>The following function takes a list of <c>person</c> records
+ and searches for the phone number of a person with a particular
+ name:</p>
+ <code type="none">
+find_phone([#person{name=Name, phone=Phone} | _], Name) ->
+ {found, Phone};
+find_phone([_| T], Name) ->
+ find_phone(T, Name);
+find_phone([], Name) ->
+ not_found.</code>
+ <p>The fields referred to in the pattern can be given in any order.</p>
+ </section>
+
+ <section>
+ <title>Nested Records</title>
+ <p>The value of a field in a record might 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>
+-record(name, {first = "Robert", last = "Ericsson"}).
+-record(person, {name = #name{}, phone}).
+
+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>
+ </section>
+
+ <section>
+ <title>Example</title>
+ <pre>
+%% File: person.hrl
+
+%%-----------------------------------------------------------
+%% Data Type: person
+%% where:
+%% name: A string (default is undefined).
+%% age: An integer (default is undefined).
+%% phone: A list of integers (default is []).
+%% dict: A dictionary containing various information
+%% about the person.
+%% A {Key, Value} list (default is the empty list).
+%%------------------------------------------------------------
+-record(person, {name, age, phone = [], dict = []}).</pre>
+ <pre>
+-module(person).
+-include("person.hrl").
+-compile(export_all). % For test purposes only.
+
+%% This creates an instance of a person.
+%% Note: The phone number is not supplied so the
+%% default value [] will be used.
+
+make_hacker_without_phone(Name, Age) ->
+ #person{name = Name, age = Age,
+ dict = [{computer_knowledge, excellent},
+ {drinks, coke}]}.
+
+%% This demonstrates matching in arguments
+
+print(#person{name = Name, age = Age,
+ phone = Phone, dict = Dict}) ->
+ io:format("Name: ~s, Age: ~w, Phone: ~w ~n"
+ "Dictionary: ~w.~n", [Name, Age, Phone, Dict]).
+
+%% Demonstrates type testing, selector, updating.
+
+birthday(P) when record(P, person) ->
+ P#person{age = P#person.age + 1}.
+
+register_two_hackers() ->
+ Hacker1 = make_hacker_without_phone("Joe", 29),
+ OldHacker = birthday(Hacker1),
+ % The central_register_server should have
+ % an interface function for this.
+ central_register_server ! {register_person, Hacker1},
+ central_register_server ! {register_person,
+ OldHacker#person{name = "Robert",
+ phone = [0,8,3,2,4,5,3,1]}}.</pre>
+ </section>
+</chapter>
+
diff --git a/system/doc/programming_examples/xmlfiles.mk b/system/doc/programming_examples/xmlfiles.mk
new file mode 100644
index 0000000000..5eb42a2881
--- /dev/null
+++ b/system/doc/programming_examples/xmlfiles.mk
@@ -0,0 +1,23 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+PROG_EX_CHAPTER_FILES = \
+ bit_syntax.xml \
+ funs.xml \
+ list_comprehensions.xml \
+ records.xml