1
<?xml version="1.0" encoding="latin1" ?>
2
<!DOCTYPE chapter SYSTEM "chapter.dtd">
7
<year>2003</year><year>2009</year>
8
<holder>Ericsson AB. All Rights Reserved.</holder>
11
The contents of this file are subject to the Erlang Public License,
12
Version 1.1, (the "License"); you may not use this file except in
13
compliance with the License. You should have received a copy of the
14
Erlang Public License along with this software. If not, it can be
15
retrieved online at http://www.erlang.org/.
17
Software distributed under the License is distributed on an "AS IS"
18
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
19
the License for the specific language governing rights and limitations
24
<title>List Comprehensions</title>
29
<file>list_comprehensions.xml</file>
33
<title>Simple Examples</title>
34
<p>We start with a simple example:</p>
36
> <input>[X || X <- [1,2,a,3,4,b,5,6], X > 3].</input>
38
<p>This should be read as follows:</p>
40
<p>The list of X such that X is taken from the list
41
<c>[1,2,a,...]</c> and X is greater than 3.</p>
43
<p>The notation <c><![CDATA[X <- [1,2,a,...]]]></c> is a generator and
44
the expression <c>X > 3</c> is a filter.</p>
45
<p>An additional filter can be added in order to restrict
46
the result to integers:</p>
48
> <input>[X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3].</input>
50
<p>Generators can be combined. For example, the Cartesian product
51
of two lists can be written as follows:</p>
53
> <input>[{X, Y} || X <- [1,2,3], Y <- [a,b]].</input>
54
[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}]</pre>
58
<title>Quick Sort</title>
59
<p>The well known quick sort routine can be written as follows:</p>
60
<code type="none"><![CDATA[
62
sort([ X || X <- T, X < Pivot]) ++
64
sort([ X || X <- T, X >= Pivot]);
65
sort([]) -> [].]]></code>
66
<p>The expression <c><![CDATA[[X || X <- T, X < Pivot]]]></c> is the list of
67
all elements in <c>T</c>, which are less than <c>Pivot</c>.</p>
68
<p><c><![CDATA[[X || X <- T, X >= Pivot]]]></c> is the list of all elements in
69
<c>T</c>, which are greater or equal to <c>Pivot</c>.</p>
70
<p>To sort a list, we isolate the first element in the list and
71
split the list into two sub-lists. The first sub-list contains
72
all elements which are smaller than the first element in
73
the list, the second contains all elements which are greater
74
than or equal to the first element in the list. We then sort
75
the sub-lists and combine the results.</p>
79
<title>Permutations</title>
80
<p>The following example generates all permutations of
81
the elements in a list:</p>
82
<code type="none"><![CDATA[
84
perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].]]></code>
85
<p>We take take <c>H</c> from <c>L</c> in all possible ways.
86
The result is the set of all lists <c>[H|T]</c>, where <c>T</c>
87
is the set of all possible permutations of <c>L</c> with
90
> <input>perms([b,u,g]).</input>
91
[[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]]</pre>
95
<title>Pythagorean Triplets</title>
96
<p>Pythagorean triplets are sets of integers <c>{A,B,C}</c> such
97
that <c>A**2 + B**2 = C**2</c>.</p>
98
<p>The function <c>pyth(N)</c> generates a list of all integers
99
<c>{A,B,C}</c> such that <c>A**2 + B**2 = C**2</c> and where
100
the sum of the sides is equal to or less than <c>N</c>.</p>
101
<code type="none"><![CDATA[
111
> <input>pyth(3).</input>
113
> <input>pyth(11).</input>
115
> <input>pyth(12).</input>
117
> <input>pyth(50).</input>
130
<p>The following code reduces the search space and is more
132
<code type="none"><![CDATA[
135
A <- lists:seq(1,N-2),
136
B <- lists:seq(A+1,N-1),
137
C <- lists:seq(B+1,N),
139
A*A+B*B == C*C ].]]></code>
143
<title>Simplifications with List Comprehensions</title>
144
<p>As an example, list comprehensions can be used to simplify some
145
of the functions in <c>lists.erl</c>:</p>
146
<code type="none"><![CDATA[
147
append(L) -> [X || L1 <- L, X <- L1].
148
map(Fun, L) -> [Fun(X) || X <- L].
149
filter(Pred, L) -> [X || X <- L, Pred(X)].]]></code>
153
<title>Variable Bindings in List Comprehensions</title>
154
<p>The scope rules for variables which occur in list
155
comprehensions are as follows:</p>
156
<list type="bulleted">
157
<item>all variables which occur in a generator pattern are
158
assumed to be "fresh" variables</item>
159
<item>any variables which are defined before the list
160
comprehension and which are used in filters have the values
161
they had before the list comprehension</item>
162
<item>no variables may be exported from a list comprehension.</item>
164
<p>As an example of these rules, suppose we want to write
165
the function <c>select</c>, which selects certain elements from
166
a list of tuples. We might write
167
<c><![CDATA[select(X, L) -> [Y || {X, Y} <- L].]]></c> with the intention
168
of extracting all tuples from <c>L</c> where the first item is
170
<p>Compiling this yields the following diagnostic:</p>
172
./FileName.erl:Line: Warning: variable 'X' shadowed in generate</code>
173
<p>This diagnostic warns us that the variable <c>X</c> in
174
the pattern is not the same variable as the variable <c>X</c>
175
which occurs in the function head.</p>
176
<p>Evaluating <c>select</c> yields the following result:</p>
178
> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input>
180
<p>This result is not what we wanted. To achieve the desired
181
effect we must write <c>select</c> as follows:</p>
182
<code type="none"><![CDATA[
183
select(X, L) -> [Y || {X1, Y} <- L, X == X1].]]></code>
184
<p>The generator now contains unbound variables and the test has
185
been moved into the filter. This now works as expected:</p>
187
> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input>
189
<p>One consequence of the rules for importing variables into a
190
list comprehensions is that certain pattern matching operations
191
have to be moved into the filters and cannot be written directly
192
in the generators. To illustrate this, do not write as follows:</p>
193
<code type="none"><![CDATA[
196
[ Expression || PatternInvolving Y <- Expr, ...]
198
<p>Instead, write as follows:</p>
199
<code type="none"><![CDATA[
202
[ Expression || PatternInvolving Y1 <- Expr, Y == Y1, ...]