SCDoc: Use proper static string constants instead of comparing string literals.
[supercollider.git] / Help / Language / ListComprehensions.html
blob262f0143b774f3a86ca4076c10d43d50922c8db4
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <meta http-equiv="Content-Style-Type" content="text/css">
6 <title></title>
7 <meta name="Generator" content="Cocoa HTML Writer">
8 <meta name="CocoaVersion" content="824.42">
9 <style type="text/css">
10 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica}
11 p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
12 p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
13 p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Monaco; min-height: 14.0px}
14 p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Monaco; color: #a71e12}
15 p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Monaco}
16 p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica}
17 p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Courier}
18 p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
19 p.p10 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica; min-height: 17.0px}
20 span.s1 {color: #0019b7}
21 span.s2 {color: #326f17}
22 span.s3 {color: #a71e12}
23 span.s4 {font: 10.0px Monaco}
24 span.s5 {color: #000000}
25 span.Apple-tab-span {white-space:pre}
26 </style>
27 </head>
28 <body>
29 <p class="p1"><b>List Comprehensions</b></p>
30 <p class="p2"><br></p>
31 <p class="p3">List comprehensions are a syntactic feature of functional programming languages like Miranda, Haskell, and Erlang which were later copied into Python.</p>
32 <p class="p3">You can search the web for "list comprehensions" or "generator expressions" to learn more.<span class="Apple-converted-space"> </span></p>
33 <p class="p3">Basically list comprehensions are for getting a series of solutions to a problem.</p>
34 <p class="p2"><br></p>
35 <p class="p3">in SC these are just a syntax macro for a longer expression.</p>
36 <p class="p4"><br></p>
37 <p class="p5">// read this as "all [x,y] for x in 1..5, y in 1..x, such that x+y is prime.</p>
38 <p class="p6">all {:[x,y], x &lt;- (1..5), y &lt;- (1..x), (x+y).isPrime }</p>
39 <p class="p4"><br></p>
40 <p class="p6">[ [ 1, 1 ], [ 2, 1 ], [ 3, 2 ], [ 4, 1 ], [ 4, 3 ], [ 5, 2 ] ]</p>
41 <p class="p4"><br></p>
42 <p class="p3">the list comprehension above is equivalent to the following code:</p>
43 <p class="p4"><br></p>
44 <p class="p6">all(<span class="s1">Routine</span>.new({ (1..5).do {<span class="s1">|x|</span> (1..x).do {<span class="s1">|y|</span> if ((x+y).isPrime) {[x,y].yield} }}}));</p>
45 <p class="p4"><br></p>
46 <p class="p3">..but much more concise and much easier to keep in your head than writing it out.</p>
47 <p class="p2"><br></p>
48 <p class="p3">In the list comprehension compiler, simple series like (1..5) and (1..x) are treated as special cases and implemented as loops rather than making a collection.</p>
49 <p class="p2"><br></p>
50 <p class="p3">A list comprehension in SC is really a Routine. You can use the 'all' message to collect all of the Routine's results into a list.</p>
51 <p class="p2"><br></p>
52 <p class="p7"><b>A few examples</b></p>
53 <p class="p4"><br></p>
54 <p class="p6">all {: x/(x+1), x &lt;- (1..5) }</p>
55 <p class="p4"><br></p>
56 <p class="p6">[ 0.5, 0.66666666666667, 0.75, 0.8, 0.83333333333333 ]</p>
57 <p class="p4"><br></p>
58 <p class="p6">all {:[x,y], x &lt;- (1..3), y &lt;- [<span class="s2">\a</span>,<span class="s2">\b</span>,<span class="s2">\c</span>] }</p>
59 <p class="p4"><br></p>
60 <p class="p6">[ [ 1, a ], [ 1, b ], [ 1, c ], [ 2, a ], [ 2, b ], [ 2, c ], [ 3, a ], [ 3, b ], [ 3, c ] ]</p>
61 <p class="p4"><br></p>
62 <p class="p6">all {:[x,y], x &lt;- (0..3), y &lt;- (x..0) }</p>
63 <p class="p4"><br></p>
64 <p class="p6">[ [ 0, 0 ], [ 1, 1 ], [ 1, 0 ], [ 2, 2 ], [ 2, 1 ], [ 2, 0 ], [ 3, 3 ], [ 3, 2 ], [ 3, 1 ], [ 3, 0 ] ]</p>
65 <p class="p4"><br></p>
66 <p class="p6">all {:y, x &lt;- (1..4), y &lt;- (x..1) }</p>
67 <p class="p4"><br></p>
68 <p class="p6">[ 1, 2, 1, 3, 2, 1, 4, 3, 2, 1 ]</p>
69 <p class="p4"><br></p>
70 <p class="p4"><br></p>
71 <p class="p6">(</p>
72 <p class="p6"><span class="s1">var</span> intervals;</p>
73 <p class="p5">// a function to generate intervals between all pairs of notes in a chord voicing</p>
74 <p class="p6">intervals = {<span class="s1">|chord|</span></p>
75 <p class="p6"><span class="Apple-tab-span"> </span>all {: chord[i+gap] - chord[i],<span class="Apple-converted-space"> </span></p>
76 <p class="p6"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>gap &lt;- (1 .. chord.lastIndex),<span class="Apple-converted-space"> </span></p>
77 <p class="p6"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>i &lt;- (0 .. chord.lastIndex - gap)<span class="Apple-converted-space"> </span></p>
78 <p class="p6"><span class="Apple-tab-span"> </span>}</p>
79 <p class="p6">};</p>
80 <p class="p4"><br></p>
81 <p class="p6">intervals.([0,4,7,10]).postln;</p>
82 <p class="p6">intervals.([0,1,3,7]).postln;</p>
83 <p class="p6">)</p>
84 <p class="p2"><br></p>
85 <p class="p6">[ 4, 3, 3, 7, 6, 10 ]</p>
86 <p class="p6">[ 1, 2, 4, 3, 6, 7 ]</p>
87 <p class="p4"><br></p>
88 <p class="p6">all {:[y, z], x&lt;-(0..30), <span class="s1">var</span> y = x.nthPrime, <span class="s1">var</span> z = 2 ** y - 1, z.asInteger.isPrime.not<span class="Apple-converted-space">  </span>}</p>
89 <p class="p6">[ [ 11, 2047 ], [ 23, 8388607 ], [ 29, 536870911 ] ] <span class="s3">// mersenne numbers which are no primes</span></p>
90 <p class="p2"><br></p>
91 <p class="p7"><b>Qualifier Clauses</b></p>
92 <p class="p2"><br></p>
93 <p class="p3">A list comprehension begins with <span class="s4">{: </span>and contains a body followed by several qualifier clauses separated by commas.</p>
94 <p class="p2"><br></p>
95 <p class="p8">{: <i>body</i> , <i>qualifiers</i> }</p>
96 <p class="p2"><br></p>
97 <p class="p3">There are several types of qualifier clauses that can appear after the body.</p>
98 <p class="p2"><br></p>
99 <p class="p3"><b>generator clause</b></p>
100 <p class="p2"><br></p>
101 <p class="p3">The basic clause is the generator clause. Its syntax is<span class="Apple-converted-space"> </span></p>
102 <p class="p2"><br></p>
103 <p class="p8"><i>name</i> &lt;- <i>expr</i></p>
104 <p class="p2"><br></p>
105 <p class="p3">The expression should be something that can respond meaningfully to 'do' such as a collection or a stream.</p>
106 <p class="p3">The name takes on each value of the expression.</p>
107 <p class="p3">The name is a local variable whose scope extends to all clauses to the right. The name is also in scope in the body.</p>
108 <p class="p2"><br></p>
109 <p class="p6">all {: x, x &lt;- (1..3) }</p>
110 <p class="p4"><br></p>
111 <p class="p6">[ 1, 2, 3 ]</p>
112 <p class="p4"><br></p>
113 <p class="p6">all {: x, x &lt;- [\a, \b, \c] }</p>
114 <p class="p4"><br></p>
115 <p class="p6">[ a, b, c ]</p>
116 <p class="p4"><br></p>
117 <p class="p6">all {: x, x &lt;- (1!3)++(2!2)++3 }</p>
118 <p class="p4"><br></p>
119 <p class="p6">[ 1, 1, 1, 2, 2, 3 ]</p>
120 <p class="p4"><br></p>
121 <p class="p3">multiple generators act like nested loops.</p>
122 <p class="p4"><br></p>
123 <p class="p6">all {: [x,y], x &lt;- (1..2), y &lt;- (10,20..30) }</p>
124 <p class="p4"><br></p>
125 <p class="p9">[ [ 1, 10 ], [ 1, 20 ], [ 1, 30 ], [ 2, 10 ], [ 2, 20 ], [ 2, 30 ] ]</p>
126 <p class="p4"><br></p>
127 <p class="p3">generators can depend on previous values.</p>
128 <p class="p4"><br></p>
129 <p class="p6">all {: x, x &lt;- (1..3), y &lt;- (1..x) }</p>
130 <p class="p4"><br></p>
131 <p class="p6">[ 1, 2, 2, 3, 3, 3 ]</p>
132 <p class="p4"><br></p>
133 <p class="p6">all {: x, x &lt;- (1..3), y &lt;- (1..4-x) }</p>
134 <p class="p4"><br></p>
135 <p class="p6">[ 1, 1, 1, 2, 2, 3 ]</p>
136 <p class="p4"><br></p>
137 <p class="p4"><br></p>
138 <p class="p3"><b>guard clause</b></p>
139 <p class="p2"><br></p>
140 <p class="p3">A guard clause is simply an expression. It should return a boolean value.<span class="Apple-converted-space"> </span></p>
141 <p class="p2"><br></p>
142 <p class="p8"><i>expr</i></p>
143 <p class="p4"><br></p>
144 <p class="p3">The guard acts as a filter on the results and constrains the search.</p>
145 <p class="p4"><br></p>
146 <p class="p6">all {: x, x &lt;- (0..10), x.odd }</p>
147 <p class="p2"><br></p>
148 <p class="p6">[ 1, 3, 5, 7, 9 ]</p>
149 <p class="p2"><br></p>
150 <p class="p3">x.odd is the guard and causes all even numbers to be skipped.</p>
151 <p class="p2"><br></p>
152 <p class="p6">all {: x, x &lt;- (0..30), (x % 5 == 0) || x.isPowerOfTwo }</p>
153 <p class="p4"><br></p>
154 <p class="p6">[ 0, 1, 2, 4, 5, 8, 10, 15, 16, 20, 25, 30 ]</p>
155 <p class="p2"><br></p>
156 <p class="p3">you can have multiple guards.</p>
157 <p class="p2"><br></p>
158 <p class="p6">all {: [x,y], x &lt;- (0..10), (x % 5 == 0) || x.isPowerOfTwo, y &lt;- (1..2), (x+y).even }</p>
159 <p class="p4"><br></p>
160 <p class="p6">[ [ 0, 2 ], [ 1, 1 ], [ 2, 2 ], [ 4, 2 ], [ 5, 1 ], [ 8, 2 ], [ 10, 2 ] ]</p>
161 <p class="p2"><br></p>
162 <p class="p2"><br></p>
163 <p class="p3"><b>var clause</b></p>
164 <p class="p2"><br></p>
165 <p class="p3">A var clause lets you create a new variable binding that you can use in your expressions.</p>
166 <p class="p3">The scope of the name extends to all clauses to the right and in the body.</p>
167 <p class="p2"><br></p>
168 <p class="p8">var <i>name</i> = <i>expr</i></p>
169 <p class="p2"><br></p>
170 <p class="p3">Unlike the generator clause, the name is bound to a single value, it doesn't iterate.</p>
171 <p class="p2"><br></p>
172 <p class="p6">all {: z, x &lt;- (1..20), <span class="s1">var</span> z = (x*x-x) div: 2, z.odd }</p>
173 <p class="p2"><br></p>
174 <p class="p6">[ 1, 3, 15, 21, 45, 55, 91, 105, 153, 171 ]</p>
175 <p class="p2"><br></p>
176 <p class="p2"><br></p>
177 <p class="p3"><b>side effect clause</b></p>
178 <p class="p2"><br></p>
179 <p class="p3">This clause lets you insert code to do some side effect like printing.</p>
180 <p class="p2"><br></p>
181 <p class="p8">:: <i>expr</i></p>
182 <p class="p2"><br></p>
183 <p class="p6">all {: z, x &lt;- (1..20), <span class="s1">var</span> z = (x*x-x) div: 2, :: [x,z].postln, z.even }</p>
184 <p class="p4"><br></p>
185 <p class="p2"><br></p>
186 <p class="p3"><b>termination clause</b></p>
187 <p class="p2"><br></p>
188 <p class="p3">The termination clause is for stopping further searching for results. Once the expression becomes false,</p>
189 <p class="p3">the routine halts.</p>
190 <p class="p2"><br></p>
191 <p class="p8">:while <i>expr</i></p>
192 <p class="p2"><br></p>
193 <p class="p5">// using a guard</p>
194 <p class="p6">all {: z, x &lt;- (1..20), <span class="s1">var</span> z = (x*x-x) div: 2,<span class="Apple-converted-space">  </span>:: [x,z].postln, z &lt; 50 }</p>
195 <p class="p4"><br></p>
196 <p class="p5">// using a termination clause</p>
197 <p class="p5">// this one stops searching, so does less work than the above.</p>
198 <p class="p6">all {: z, x &lt;- (1..20), <span class="s1">var</span> z = (x*x-x) div: 2,<span class="Apple-converted-space">  </span>:: [x,z].postln, :while z &lt; 50 }</p>
199 <p class="p2"><br></p>
200 <p class="p7"><b>Constrained Search</b></p>
201 <p class="p2"><br></p>
202 <p class="p3">list comprehensions can solve constrained combinatorial problems like this one:</p>
203 <p class="p2"><br></p>
204 <p class="p3">Baker, Cooper, Fletcher, Miller, and Smith live on different floors of an apartment house that contains only five floors.</p>
205 <p class="p3">Baker does not live on the top floor. Cooper does not live on the bottom floor.</p>
206 <p class="p3">Fletcher does not live on either the top or the bottom floor. Miller lives on a higher floor than does Cooper.</p>
207 <p class="p3">Smith does not live on a floor adjacent to Fletcher's. Fletcher does not live on a floor adjacent to Cooper's.</p>
208 <p class="p3">Where does everyone live?</p>
209 <p class="p2"><br></p>
210 <p class="p6">(</p>
211 <p class="p6">z = {: [baker, cooper, fletcher, miller, smith] ,</p>
212 <p class="p6"><span class="Apple-tab-span"> </span><span class="s1">var</span> floors = (1..5),</p>
213 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span>baker &lt;- floors,<span class="Apple-converted-space">  </span>baker != 5,<span class="Apple-converted-space">  </span></span>// Baker does not live on the top floor.</p>
214 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span></span>// remove baker's floor from the list. var creates a new scope, so the 'floors' on the left is a new binding.</p>
215 <p class="p6"><span class="Apple-tab-span"> </span><span class="s1">var</span> floors = floors.removing(baker),<span class="Apple-converted-space"> </span></p>
216 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span>cooper &lt;- floors, cooper != 1, </span>// Cooper does not live on the bottom floor.</p>
217 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span></span><span class="s1">var</span><span class="s5"> floors = floors.removing(cooper), </span>// remove cooper's floor from the list.</p>
218 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span>fletcher &lt;- floors, (fletcher != 5) &amp;&amp; (fletcher != 1) </span>// Fletcher does not live on either the top or the bottom floor.</p>
219 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>&amp;&amp; (absdif(fletcher, cooper) &gt; 1), </span>// Fletcher does not live on a floor adjacent to Cooper's.</p>
220 <p class="p6"><span class="Apple-tab-span"> </span><span class="s1">var</span> floors = floors.removing(fletcher), <span class="s3">// remove fletcher's floor</span></p>
221 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span>miller &lt;- floors, miller &gt; cooper, </span>// Miller lives on a higher floor than does Cooper.</p>
222 <p class="p6"><span class="Apple-tab-span"> </span><span class="s1">var</span> floors = floors.removing(miller), <span class="s3">// remove miller's floor</span></p>
223 <p class="p5"><span class="s5"><span class="Apple-tab-span"> </span>smith &lt;- floors, absdif(fletcher, smith) &gt; 1<span class="Apple-converted-space">  </span></span>// Smith does not live on a floor adjacent to Fletcher's.</p>
224 <p class="p6">};</p>
225 <p class="p6">)</p>
226 <p class="p4"><br></p>
227 <p class="p5"><span class="s5">z.next; </span>// [3, 2, 4, 5, 1 ]</p>
228 <p class="p5"><span class="s5">z.next; </span>// nil.<span class="Apple-converted-space">  </span>only one solution</p>
229 <p class="p4"><br></p>
230 <p class="p3">combinatorial problems can take a lot of time to run.</p>
231 <p class="p3">you can reorder the above tests to make it run faster. generally you want to search the most constrained variables first.</p>
232 <p class="p3">the most constrained person above is fletcher, so he should be searched first, then cooper, etc.</p>
233 <p class="p4"><br></p>
234 <p class="p4"><br></p>
235 <p class="p4"><br></p>
236 <p class="p7"><b>Grammar:</b></p>
237 <p class="p10"><br></p>
238 <p class="p3">Here is the BNF grammar for list comprehensions in SC.</p>
239 <p class="p4"><br></p>
240 <p class="p6">[ ] - optional</p>
241 <p class="p6">{ } - zero or more</p>
242 <p class="p4"><br></p>
243 <p class="p6">&lt;list_compre&gt; ::= "{:" &lt;body&gt; ',' &lt;qualifiers&gt; "}"</p>
244 <p class="p4"><br></p>
245 <p class="p6">&lt;body&gt; ::= &lt;exprseq&gt;</p>
246 <p class="p4"><br></p>
247 <p class="p6">&lt;exprseq&gt; ::= &lt;expr&gt; { ";" &lt;expr&gt; }</p>
248 <p class="p4"><br></p>
249 <p class="p6">&lt;qualifiers&gt; ::= &lt;qualifier&gt; { ',' &lt;qualifiers&gt; }</p>
250 <p class="p4"><br></p>
251 <p class="p6">&lt;qualifier&gt; ::= &lt;generator&gt; | &lt;guard&gt; | &lt;binding&gt; | &lt;side_effect&gt; | &lt;termination&gt;</p>
252 <p class="p4"><br></p>
253 <p class="p6">&lt;generator&gt; ::= &lt;name&gt; "&lt;-" &lt;exprseq&gt;</p>
254 <p class="p4"><br></p>
255 <p class="p6">&lt;guard&gt; ::= &lt;exprseq&gt;</p>
256 <p class="p4"><br></p>
257 <p class="p6">&lt;binding&gt; ::= "var" &lt;name&gt; "=" &lt;exprseq&gt;</p>
258 <p class="p4"><br></p>
259 <p class="p6">&lt;side_effect&gt; ::= "::" &lt;exprseq&gt;</p>
260 <p class="p4"><br></p>
261 <p class="p6">&lt;termination&gt; ::= ":while" &lt;exprseq&gt;</p>
262 <p class="p4"><br></p>
263 <p class="p4"><br></p>
264 <p class="p7"><b>Code Generation:</b></p>
265 <p class="p4"><br></p>
266 <p class="p3">For each of the above clauses, here is how the code is generated. The body acts as the innermost qualifier.</p>
267 <p class="p3">By understanding these translations, you can better understand how scoping and control flow work in list comprehensions.</p>
268 <p class="p4"><br></p>
269 <p class="p3"><b>generator:</b></p>
270 <p class="p4"><br></p>
271 <p class="p6">expr.do {|name| ..next qualifier.. }</p>
272 <p class="p4"><br></p>
273 <p class="p4"><br></p>
274 <p class="p3"><b>guard:</b></p>
275 <p class="p4"><br></p>
276 <p class="p6">if (expr) { ..next qualifier.. }</p>
277 <p class="p4"><br></p>
278 <p class="p4"><br></p>
279 <p class="p3"><b>binding:</b></p>
280 <p class="p4"><br></p>
281 <p class="p6">{|name| ..next qualifier.. }.value(expr)</p>
282 <p class="p4"><br></p>
283 <p class="p4"><br></p>
284 <p class="p3"><b>side effect:</b></p>
285 <p class="p4"><br></p>
286 <p class="p6">expr ; ..next qualifier..</p>
287 <p class="p4"><br></p>
288 <p class="p4"><br></p>
289 <p class="p3"><b>termination:</b></p>
290 <p class="p4"><br></p>
291 <p class="p6">if (expr) { ..next qualifier.. }{ nil.alwaysYield }</p>
292 <p class="p4"><br></p>
293 </body>
294 </html>