forked from racket/racket
/
for.scrbl
573 lines (479 loc) · 19.7 KB
/
for.scrbl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
#lang scribble/doc
@(require "mz.rkt")
@title[#:tag "for"]{Iterations and Comprehensions: @racket[for], @racket[for/list], ...}
@guideintro["for"]{iterations and comprehensions}
@(define for-eval (make-base-eval))
@(for-eval '(require (for-syntax racket/base)))
The @racket[for] iteration forms are based on SRFI-42
@cite["SRFI-42"].
@section{Iteration and Comprehension Forms}
@defform/subs[(for (for-clause ...) body-or-break ... body)
([for-clause [id seq-expr]
[(id ...) seq-expr]
(code:line #:when guard-expr)
(code:line #:unless guard-expr)
break-clause]
[break-clause (code:line #:break guard-expr)
(code:line #:final guard-expr)]
[body-or-break body
bleak-clause])
#:contracts ([seq-expr sequence?])]{
Iteratively evaluates @racket[body]s. The @racket[for-clause]s
introduce bindings whose scope includes @racket[body] and that
determine the number of times that @racket[body] is evaluated.
A @racket[break-clause] either among the @racket[for-clause]s
of @racket[body]s stops further iteration.
In the simple case, each @racket[for-clause] has one of its first two
forms, where @racket[[id seq-expr]] is a shorthand for @racket[[(id)
seq-expr]]. In this simple case, the @racket[seq-expr]s are evaluated
left-to-right, and each must produce a sequence value (see
@secref["sequences"]).
The @racket[for] form iterates by drawing an element from each
sequence; if any sequence is empty, then the iteration stops, and
@|void-const| is the result of the @racket[for] expression. Otherwise
a location is created for each @racket[id] to hold the values of each
element; the sequence produced by a @racket[seq-expr] must return as
many values for each iteration as corresponding @racket[id]s.
The @racket[id]s are then bound in the @racket[body], which is
evaluated, and whose results are ignored. Iteration continues with the
next element in each sequence and with fresh locations for each
@racket[id].
A @racket[for] form with zero @racket[for-clause]s is equivalent to a
single @racket[for-clause] that binds an unreferenced @racket[id] to
a sequence containing a single element. All of the @racket[id]s must
be distinct according to @racket[bound-identifier=?].
If any @racket[for-clause] has the form @racket[#:when guard-expr],
then only the preceding clauses (containing no @racket[#:when] or @racket[#:unless])
determine iteration as above, and the @racket[body] is effectively
wrapped as
@racketblock[
(when guard-expr
(for (for-clause ...) body ...+))
]
using the remaining @racket[for-clauses]. A @racket[for-clause] of
the form @racket[#:unless guard-expr] corresponds to the same transformation
with @racket[unless] in place of @racket[when].
A @racket[#:break guard-expr] clause is similar to a
@racket[#:unless guard-expr] clause, but when @racket[#:break]
avoids evaluation of the @racket[body]s, it also effectively ends all
sequences within the @racket[for] form. A @racket[#:final
guard-expr] clause is similar to @racket[#:break guard-expr], but
instead of immediately ending sequences and skipping the
@racket[body]s, it allows at most one more element from each later
sequence and at most one more evaluation of the following
@racket[body]s. Among the @racket[body]s, besides stopping the
iteration and preventing later @racket[body] evaluations, a
@racket[#:break guard-expr] or @racket[#:final guard-expr]
clause starts a new internal-definition context.
@examples[
(for ([i '(1 2 3)]
[j "abc"]
#:when (odd? i)
[k #2(#t #f)])
(display (list i j k)))
(for ([(i j) #hash(("a" . 1) ("b" . 20))])
(display (list i j)))
(for ([i '(1 2 3)]
[j "abc"]
#:break (not (odd? i))
[k #2(#t #f)])
(display (list i j k)))
(for ([i '(1 2 3)]
[j "abc"]
#:final (not (odd? i))
[k #2(#t #f)])
(display (list i j k)))
(for ([i '(1 2 3)]
[j "abc"]
[k #2(#t #f)])
#:break (not (or (odd? i) k))
(display (list i j k)))
(for ()
(display "here"))
(for ([i '()])
(error "doesn't get here"))
]}
@defform[(for/list (for-clause ...) body-or-break ... body)]{ Iterates like
@racket[for], but that the last expression in the @racket[body]s must
produce a single value, and the result of the @racket[for/list]
expression is a list of the results in order.
When evaluation of a @racket[body] is skipped due to a @racket[#:when]
or @racket[#:unless] clause, the result list includes no corresponding
element.
@examples[
(for/list ([i '(1 2 3)]
[j "abc"]
#:when (odd? i)
[k #2(#t #f)])
(list i j k))
(for/list ([i '(1 2 3)]
[j "abc"]
#:break (not (odd? i))
[k #2(#t #f)])
(list i j k))
(for/list () 'any)
(for/list ([i '()])
(error "doesn't get here"))
]}
@defform/subs[(for/vector maybe-length (for-clause ...) body-or-break ... body)
([maybe-length (code:line)
(code:line #:length length-expr)
(code:line #:length length-expr #:fill fill-expr)])
#:contracts ([length-expr exact-nonnegative-integer?])]{
Iterates like @racket[for/list], but results are accumulated into
a vector instead of a list.
If the optional @racket[#:length] clause is specified, the result of
@racket[length-expr] determines the length of the result vector. In
that case, the iteration can be performed more efficiently, and it
terminates when the vector is full or the requested number of
iterations have been performed, whichever comes first. If
@racket[length-expr] specifies a length longer than the number of
iterations, then the remaining slots of the vector are initialized to
the value of @racket[fill-expr], which defaults to @racket[0] (i.e.,
the default argument of @racket[make-vector]).
@examples[
(for/vector ([i '(1 2 3)]) (number->string i))
(for/vector #:length 2 ([i '(1 2 3)]) (number->string i))
(for/vector #:length 4 ([i '(1 2 3)]) (number->string i))
(for/vector #:length 4 #:fill "?" ([i '(1 2 3)]) (number->string i))
]
The @racket[for/vector] form may allocate a vector and mutate it after
each iteration of @racket[body], which means that capturing a
continuation during @racket[body] and applying it multiple times may
mutate a shared vector.}
@deftogether[(
@defform[(for/hash (for-clause ...) body-or-break ... body)]
@defform[(for/hasheq (for-clause ...) body-or-break ... body)]
@defform[(for/hasheqv (for-clause ...) body-or-break ... body)]
)]{
Like @racket[for/list], but the result is an immutable @tech{hash
table}; @racket[for/hash] creates a table using @racket[equal?] to
distinguish keys, @racket[for/hasheq] produces a table using
@racket[eq?], and @racket[for/hasheqv] produces a table using
@racket[eqv?]. The last expression in the @racket[body]s must return
two values: a key and a value to extend the hash table accumulated by
the iteration.
@examples[
(for/hash ([i '(1 2 3)])
(values i (number->string i)))
]}
@defform[(for/and (for-clause ...) body-or-break ... body)]{ Iterates like
@racket[for], but when last expression of @racket[body] produces
@racket[#f], then iteration terminates, and the result of the
@racket[for/and] expression is @racket[#f]. If the @racket[body]
is never evaluated, then the result of the @racket[for/and]
expression is @racket[#t]. Otherwise, the result is the (single)
result from the last evaluation of @racket[body].
@examples[
(for/and ([i '(1 2 3 "x")])
(i . < . 3))
(for/and ([i '(1 2 3 4)])
i)
(for/and ([i '(1 2 3 4)])
#:break (= i 3)
i)
(for/and ([i '()])
(error "doesn't get here"))
]}
@defform[(for/or (for-clause ...) body-or-break ... body)]{ Iterates like
@racket[for], but when last expression of @racket[body] produces
a value other than @racket[#f], then iteration terminates, and
the result of the @racket[for/or] expression is the same
(single) value. If the @racket[body] is never evaluated, then the
result of the @racket[for/or] expression is
@racket[#f]. Otherwise, the result is @racket[#f].
@examples[
(for/or ([i '(1 2 3 "x")])
(i . < . 3))
(for/or ([i '(1 2 3 4)])
i)
(for/or ([i '()])
(error "doesn't get here"))
]}
@deftogether[(
@defform[(for/sum (for-clause ...) body-or-break ... body)]
)]{
Iterates like @racket[for], but each result of the last @racket[body]
is accumulated into a result with @racket[+].
@examples[
(for/sum ([i '(1 2 3 4)]) i)
]}
@deftogether[(
@defform[(for/product (for-clause ...) body-or-break ... body)]
)]{
Iterates like @racket[for], but each result of the last @racket[body]
is accumulated into a result with @racket[*].
@examples[
(for/product ([i '(1 2 3 4)]) i)
]}
@defform[(for/lists (id ...) (for-clause ...) body-or-break ... body)]{
Similar to @racket[for/list], but the last @racket[body] expression
should produce as many values as given @racket[id]s, and the result is
as many lists as supplied @racket[id]s. The @racket[id]s are bound to
the lists accumulated so far in the @racket[for-clause]s and
@racket[body]s.}
@defform[(for/first (for-clause ...) body-or-break ... body)]{ Iterates like
@racket[for], but after @racket[body] is evaluated the first
time, then the iteration terminates, and the @racket[for/first]
result is the (single) result of @racket[body]. If the
@racket[body] is never evaluated, then the result of the
@racket[for/first] expression is @racket[#f].
@examples[
(for/first ([i '(1 2 3 "x")]
#:when (even? i))
(number->string i))
(for/first ([i '()])
(error "doesn't get here"))
]}
@defform[(for/last (for-clause ...) body-or-break ... body)]{ Iterates like
@racket[for], but the @racket[for/last] result is the (single)
result of the last evaluation of @racket[body]. If the
@racket[body] is never evaluated, then the result of the
@racket[for/last] expression is @racket[#f].
@examples[
(for/last ([i '(1 2 3 4 5)]
#:when (even? i))
(number->string i))
(for/last ([i '()])
(error "doesn't get here"))
]}
@defform[(for/fold ([accum-id init-expr] ...) (for-clause ...)
body-or-break ... body)]{
Iterates like @racket[for]. Before iteration starts, the
@racket[init-expr]s are evaluated to produce initial accumulator
values. At the start of each iteration, a location is generated
for each @racket[accum-id], and the corresponding current accumulator
value is placed into the location. The last expression in
@racket[body] must produce as many values as @racket[accum-id]s, and
those values become the current accumulator values. When iteration
terminates, the results of the @racket[fold/for] expression are the
accumulator values.
@examples[
(for/fold ([sum 0]
[rev-roots null])
([i '(1 2 3 4)])
(values (+ sum i) (cons (sqrt i) rev-roots)))
]}
@defform[(for* (for-clause ...) body-or-break ... body)]{
Like @racket[for], but with an implicit @racket[#:when #t] between
each pair of @racket[for-clauses], so that all sequence iterations are
nested.
@examples[
(for* ([i '(1 2)]
[j "ab"])
(display (list i j)))
]}
@deftogether[(
@defform[(for*/list (for-clause ...) body-or-break ... body)]
@defform[(for*/lists (id ...) (for-clause ...) body-or-break ... body)]
@defform[(for*/vector maybe-length (for-clause ...) body-or-break ... body)]
@defform[(for*/hash (for-clause ...) body-or-break ... body)]
@defform[(for*/hasheq (for-clause ...) body-or-break ... body)]
@defform[(for*/hasheqv (for-clause ...) body-or-break ... body)]
@defform[(for*/and (for-clause ...) body-or-break ... body)]
@defform[(for*/or (for-clause ...) body-or-break ... body)]
@defform[(for*/sum (for-clause ...) body-or-break ... body)]
@defform[(for*/product (for-clause ...) body-or-break ... body)]
@defform[(for*/first (for-clause ...) body-or-break ... body)]
@defform[(for*/last (for-clause ...) body-or-break ... body)]
@defform[(for*/fold ([accum-id init-expr] ...) (for-clause ...)
body-or-break ... body)]
)]{
Like @racket[for/list], etc., but with the implicit nesting of
@racket[for*].
@examples[
(for*/list ([i '(1 2)]
[j "ab"])
(list i j))
]}
@;------------------------------------------------------------------------
@section{Deriving New Iteration Forms}
@defform[(for/fold/derived orig-datum
([accum-id init-expr] ...) (for-clause ...)
body-or-break ... body)]{
Like @racket[for/fold], but the extra @racket[orig-datum] is used as the
source for all syntax errors.
@mz-examples[#:eval for-eval
(define-syntax (for/digits stx)
(syntax-case stx ()
[(_ clauses . defs+exprs)
(with-syntax ([original stx])
#'(let-values
([(n k)
(for/fold/derived original ([n 0] [k 1]) clauses
(define d (let () . defs+exprs))
(values (+ n (* d k)) (* k 10)))])
n))]))
@code:comment{If we misuse for/digits, we can get good error reporting}
@code:comment{because the use of orig-datum allows for source correlation:}
(for/digits
[a (in-list '(1 2 3))]
[b (in-list '(4 5 6))]
(+ a b))
(for/digits
([a (in-list '(1 2 3))]
[b (in-list '(2 4 6))])
(+ a b))
@code:comment{Another example: compute the max during iteration:}
(define-syntax (for/max stx)
(syntax-case stx ()
[(_ clauses . defs+exprs)
(with-syntax ([original stx])
#'(for/fold/derived original
([current-max -inf.0])
clauses
(define maybe-new-max
(let () . defs+exprs))
(if (> maybe-new-max current-max)
maybe-new-max
current-max)))]))
(for/max ([n '(3.14159 2.71828 1.61803)]
[s '(-1 1 1)])
(* n s))
]
}
@defform[(for*/fold/derived orig-datum
([accum-id init-expr] ...) (for-clause ...)
body-or-break ... body)]{
Like @racket[for*/fold], but the extra @racket[orig-datum] is used as the source for all syntax errors.
@mz-examples[#:eval for-eval
(define-syntax (for*/digits stx)
(syntax-case stx ()
[(_ clauses . defs+exprs)
(with-syntax ([original stx])
#'(let-values
([(n k)
(for*/fold/derived original ([n 0] [k 1]) clauses
(define d (let () . defs+exprs))
(values (+ n (* d k)) (* k 10)))])
n))]))
(for*/digits
[ds (in-list '((8 3) (1 1)))]
[d (in-list ds)]
d)
(for*/digits
([ds (in-list '((8 3) (1 1)))]
[d (in-list ds)])
d)
]
}
@defform[(define-sequence-syntax id
expr-transform-expr
clause-transform-expr)
#:contracts
([expr-transform-expr (or/c (-> identifier?)
(syntax? . -> . syntax?))]
[clause-transform-expr (syntax? . -> . syntax?)])]{
Defines @racket[id] as syntax. An @racket[(id . _rest)] form is
treated specially when used to generate a sequence in a
@racket[_clause] of @racket[for] (or one of its variants). In that
case, the procedure result of @racket[clause-transform-expr] is called
to transform the clause.
When @racket[id] is used in any other expression position, the result
of @racket[expr-transform-expr] is used. If it is a procedure of zero
arguments, then the result must be an identifier @racket[_other-id],
and any use of @racket[id] is converted to a use of
@racket[_other-id]. Otherwise,@racket[expr-transform-expr] must
produce a procedure (of one argument) that is used as a macro
transformer.
When the @racket[clause-transform-expr] transformer is used, it is
given a @racket[_clause] as an argument, where the clause's form is
normalized so that the left-hand side is a parenthesized sequence of
identifiers. The right-hand side is of the form @racket[(id . _rest)].
The result can be either @racket[#f], to indicate that the forms
should not be treated specially (perhaps because the number of bound
identifiers is inconsistent with the @racket[(id . _rest)] form), or a
new @racket[_clause] to replace the given one. The new clause might
use @racket[:do-in]. To protect identifiers in the result of
@racket[clause-transform-expr], use @racket[for-clause-syntax-protect]
instead of @racket[syntax-protect].
@mz-examples[#:eval for-eval
(define-sequence-syntax in-digits
(lambda () #'in-digits/proc)
(lambda (stx)
(syntax-case stx ()
[[(d) (_ nat)]
#'[(d)
(:do-in
([(n) nat])
(unless (exact-nonnegative-integer? n)
(raise-type-error 'in-digits "exact non-negative integer" n))
([i n])
(not (zero? i))
([(j d) (quotient/remainder i 10)])
#true
#true
[j])]])))
(define (in-digits/proc n [b 10])
(for/list ([d (in-digits n)]) d))
(for/list ([d (in-digits 1138)]) d)
(map in-digits (list 137 216))
]}
@defform[(:do-in ([(outer-id ...) outer-expr] ...)
outer-check
([loop-id loop-expr] ...)
pos-guard
([(inner-id ...) inner-expr] ...)
pre-guard
post-guard
(loop-arg ...))]{
A form that can only be used as a @racket[_seq-expr] in a
@racket[_clause] of @racket[for] (or one of its variants).
Within a @racket[for], the pieces of the @racket[:do-in] form are
spliced into the iteration essentially as follows:
@racketblock[
(let-values ([(outer-id ...) outer-expr] ...)
outer-check
(let loop ([loop-id loop-expr] ...)
(if pos-guard
(let-values ([(inner-id ...) inner-expr] ...)
(if pre-guard
(let _body-bindings
(if post-guard
(loop loop-arg ...)
_done-expr))
_done-expr))
_done-expr)))
]
where @racket[_body-bindings] and @racket[_done-expr] are from the
context of the @racket[:do-in] use. The identifiers bound by the
@racket[for] clause are typically part of the @racket[([(inner-id ...)
inner-expr] ...)] section.
The actual @racket[loop] binding and call has additional loop
arguments to support iterations in parallel with the @racket[:do-in]
form, and the other pieces are similarly accompanied by pieces from
parallel iterations.
For an example of @racket[:do-in], see @racket[define-sequence-syntax].}
@defproc[(for-clause-syntax-protect [stx syntax?]) syntax?]{
Provided @racket[for-syntax]: Like @racket[syntax-protect], but allows
the @racket[for] expander to @tech{disarm} the result syntax object,
and arms the pieces of a clause instead of the entire syntax object.
Use this function to protect the result of a
@racket[_clause-transform-expr] that is bound by
@racket[define-sequence-syntax].}
@section{Do Loops}
@defform/subs[(do ([id init-expr step-expr-maybe] ...)
(stop?-expr finish-expr ...)
expr ...)
([step-expr-maybe code:blank
step-expr])]{
Iteratively evaluates the @racket[expr]s for as long as
@racket[stop?-expr] returns @racket[#f].
To initialize the loop, the @racket[init-expr]s are evaluated in order
and bound to the corresponding @racket[id]s. The @racket[id]s are
bound in all expressions within the form other than the
@racket[init-expr]s.
After the @racket[id]s have been bound, the @racket[stop?-expr] is
evaluated. If it produces @racket[#f], each @racket[expr] is evaluated
for its side-effect. The @racket[id]s are then effectively updated
with the values of the @racket[step-expr]s, where the default
@racket[step-expr] for @racket[id] is just @racket[id]; more
precisely, iteration continues with fresh locations for the
@racket[id]s that are initialized with the values of the corresponding
@racket[step-expr]s.
When @racket[stop?-expr] produces a true value, then the
@racket[finish-expr]s are evaluated in order, and the last one is
evaluated in tail position to produce the overall value for the
@racket[do] form. If no @racket[finish-expr] is provided, the value of
the @racket[do] form is @|void-const|.}
@close-eval[for-eval]