racket/collects/scribblings/reference/for.scrbl
Matthew Flatt 3bb120545f fix ~300 typos reported by Vladimir Nesterovich (a.k.a. Gwyth)
--- but Gwyth's amazingly helpful review of chapters 1-11
     pointed out a few problems that are more difficult to fix
     and are still pending
2011-01-04 09:53:31 -07:00

368 lines
13 KiB
Racket

#lang scribble/doc
@(require "mz.ss")
@title[#:tag "for"]{Iterations and Comprehensions: @scheme[for], @scheme[for/list], ...}
@guideintro["for"]{iterations and comprehensions}
The @scheme[for] iteration forms are based on SRFI-42
@cite["SRFI-42"].
@section{Iteration and Comprehension Forms}
@defform/subs[(for (for-clause ...) body ...+)
([for-clause [id seq-expr]
[(id ...) seq-expr]
(code:line #:when guard-expr)])
#:contracts ([seq-expr sequence?])]{
Iteratively evaluates @scheme[body]. The @scheme[for-clause]s
introduce bindings whose scope includes @scheme[body] and that
determine the number of times that @scheme[body] is evaluated.
In the simple case, each @scheme[for-clause] has one of its first two
forms, where @scheme[[id seq-expr]] is a shorthand for @scheme[[(id)
seq-expr]]. In this simple case, the @scheme[seq-expr]s are evaluated
left-to-right, and each must produce a sequence value (see
@secref["sequences"]).
The @scheme[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 @scheme[for] expression. Otherwise
a location is created for each @scheme[id] to hold the values of each
element; the sequence produced by a @scheme[seq-expr] must return as
many values for each iteration as corresponding @scheme[id]s.
The @scheme[id]s are then bound in the @scheme[body], which is
evaluated, and whose results are ignored. Iteration continues with the
next element in each sequence and with fresh locations for each
@scheme[id].
A @scheme[for] form with zero @scheme[for-clause]s is equivalent to a
single @scheme[for-clause] that binds an unreferenced @scheme[id] to
a sequence containing a single element. All of the @scheme[id]s must
be distinct according to @scheme[bound-identifier=?].
If any @scheme[for-clause] has the form @scheme[#:when guard-expr],
then only the preceding clauses (containing no @scheme[#:when])
determine iteration as above, and the @scheme[body] is effectively
wrapped as
@schemeblock[
(when guard-expr
(for (for-clause ...) body ...+))
]
using the remaining @scheme[for-clauses].
@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 ()
(display "here"))
(for ([i '()])
(error "doesn't get here"))
]}
@defform[(for/list (for-clause ...) body ...+)]{ Iterates like
@scheme[for], but that the last expression in the @scheme[body]s must
produce a single value, and the result of the @scheme[for/list]
expression is a list of the results in order.
@examples[
(for/list ([i '(1 2 3)]
[j "abc"]
#:when (odd? i)
[k #2(#t #f)])
(list i j k))
(for/list () 'any)
(for/list ([i '()])
(error "doesn't get here"))
]}
@defform*[((for/vector (for-clause ...) body ...+)
(for/vector #:length length-expr (for-clause ...) body ...+))]{
Iterates like @scheme[for], but the last expression
in the @scheme[body]s must produce a single value, which is placed in
the corresponding slot of a vector. If the optional @scheme[#:length]
form is used, then @scheme[length-expr] must evaluate to an
@scheme[exact-nonnegative-integer?], and the result vector is
constructed with this length. In this case, the iteration can be
performed more efficiently, and terminates when the vector is full or
the requested number of iterations have been performed, whichever
comes first. If the provided @scheme[length-expr] evaluates to a
length longer than the number of iterations then the remaining slots
of the vector are intialized to the default argument of
@scheme[make-vector].}
@deftogether[(
@defform[(for/hash (for-clause ...) body ...+)]
@defform[(for/hasheq (for-clause ...) body ...+)]
@defform[(for/hasheqv (for-clause ...) body ...+)]
)]{
Like @scheme[for/list], but the result is an immutable @tech{hash
table}; @scheme[for/hash] creates a table using @scheme[equal?] to
distinguish keys, @scheme[for/hasheq] produces a table using
@scheme[eq?], and @scheme[for/hasheqv] produces a table using
@scheme[eqv?]. The last expression in the @scheme[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 ...+)]{ Iterates like
@scheme[for], but when last expression of @scheme[body] produces
@scheme[#f], then iteration terminates, and the result of the
@scheme[for/and] expression is @scheme[#f]. If the @scheme[body]
is never evaluated, then the result of the @scheme[for/and]
expression is @scheme[#t]. Otherwise, the result is the (single)
result from the last evaluation of @scheme[body].
@examples[
(for/and ([i '(1 2 3 "x")])
(i . < . 3))
(for/and ([i '(1 2 3 4)])
i)
(for/and ([i '()])
(error "doesn't get here"))
]}
@defform[(for/or (for-clause ...) body ...+)]{ Iterates like
@scheme[for], but when last expression of @scheme[body] produces
a value other than @scheme[#f], then iteration terminates, and
the result of the @scheme[for/or] expression is the same
(single) value. If the @scheme[body] is never evaluated, then the
result of the @scheme[for/or] expression is
@scheme[#f]. Otherwise, the result is @scheme[#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"))
]}
@defform[(for/lists (id ...) (for-clause ...) body ...+)]{
Similar to @scheme[for/list], but the last @scheme[body] expression
should produce as many values as given @scheme[id]s, and the result is
as many lists as supplied @scheme[id]s. The @scheme[id]s are bound to
the lists accumulated so far in the @scheme[for-clause]s and
@scheme[body]s.}
@defform[(for/first (for-clause ...) body ...+)]{ Iterates like
@scheme[for], but after @scheme[body] is evaluated the first
time, then the iteration terminates, and the @scheme[for/first]
result is the (single) result of @scheme[body]. If the
@scheme[body] is never evaluated, then the result of the
@scheme[for/first] expression is @scheme[#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 ...+)]{ Iterates like
@scheme[for], but the @scheme[for/last] result is the (single)
result of the last evaluation of @scheme[body]. If the
@scheme[body] is never evaluated, then the result of the
@scheme[for/last] expression is @scheme[#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)]{
Iterates like @scheme[for]. Before iteration starts, the
@scheme[init-expr]s are evaluated to produce initial accumulator
values. At the start of each iteration, a location is generated
for each @scheme[accum-id], and the corresponding current accumulator
value is placed into the location. The last expression in
@scheme[body] must produce as many values as @scheme[accum-id]s, and
those values become the current accumulator values. When iteration
terminates, the results of the @scheme[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 ...+)]{
Like @scheme[for], but with an implicit @scheme[#:when #t] between
each pair of @scheme[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 ...+)]
@defform[(for*/lists (id ...) (for-clause ...) body ...+)]
@defform*[((for*/vector (for-clause ...) body ...+)
(for*/vector #:length length-expr (for-clause ...) body ...+))]
@defform[(for*/hash (for-clause ...) body ...+)]
@defform[(for*/hasheq (for-clause ...) body ...+)]
@defform[(for*/hasheqv (for-clause ...) body ...+)]
@defform[(for*/and (for-clause ...) body ...+)]
@defform[(for*/or (for-clause ...) body ...+)]
@defform[(for*/first (for-clause ...) body ...+)]
@defform[(for*/last (for-clause ...) body ...+)]
@defform[(for*/fold ([accum-id init-expr] ...) (for-clause ...) body ...+)]
)]{
Like @scheme[for/list], etc., but with the implicit nesting of
@scheme[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 ...+)]{
Like @scheme[for/fold], but the extra @scheme[orig-datum] is used as the source for all syntax errors.
}
@defform[(for*/fold/derived orig-datum
([accum-id init-expr] ...) (for-clause ...) body ...+)]{
Like @scheme[for*/fold], but the extra @scheme[orig-datum] is used as the source for all syntax errors.
}
@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 @scheme[id] as syntax. An @scheme[(id . _rest)] form is
treated specially when used to generate a sequence in a
@scheme[_clause] of @scheme[for] (or one of its variants). In that
case, the procedure result of @scheme[clause-transform-expr] is called
to transform the clause.
When @scheme[id] is used in any other expression position, the result
of @scheme[expr-transform-expr] is used. If it is a procedure of zero
arguments, then the result must be an identifier @scheme[_other-id],
and any use of @scheme[id] is converted to a use of
@scheme[_other-id]. Otherwise,@scheme[expr-transform-expr] must
produce a procedure (of one argument) that is used as a macro
transformer.
When the @scheme[clause-transform-expr] transformer is used, it is
given a @scheme[_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 @scheme[(id . _rest)].
The result can be either @scheme[#f], to indicate that the forms
should not be treated specially (perhaps because the number of bound
identifiers is inconsistent with the @scheme[(id . _rest)] form), or a
new @scheme[_clause] to replace the given one. The new clause might
use @scheme[:do-in].}
@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 @scheme[_seq-expr] in a
@scheme[_clause] of @scheme[for] (or one of its variants).
Within a @scheme[for], the pieces of the @scheme[:do-in] form are
spliced into the iteration essentially as follows:
@schemeblock[
(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 @scheme[_body-bindings] and @scheme[_done-expr] are from the
context of the @scheme[:do-in] use. The identifiers bound by the
@scheme[for] clause are typically part of the @scheme[([(inner-id ...)
inner-expr] ...)] section.
The actual @scheme[loop] binding and call has additional loop
arguments to support iterations in parallel with the @scheme[:do-in]
form, and the other pieces are similarly accompanied by pieces from
parallel iterations.}
@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 @scheme[expr]s for as long as
@scheme[stop?-expr] returns @scheme[#f].
To initialize the loop, the @scheme[init-expr]s are evaluated in order
and bound to the corresponding @scheme[id]s. The @scheme[id]s are
bound in all expressions within the form other than the
@scheme[init-expr]s.
After the @scheme[id]s have been bound, the @scheme[stop?-expr] is
evaluated. If it produces @scheme[#f], each @scheme[expr] is evaluated
for its side-effect. The @scheme[id]s are then effectively updated
with the values of the @scheme[step-expr]s, where the default
@scheme[step-expr] for @scheme[id] is just @scheme[id]; more
precisely, iteration continues with fresh locations for the
@scheme[id]s that are initialized with the values of the corresponding
@scheme[step-expr]s.
When @scheme[stop?-expr] produces a true value, then the
@scheme[finish-expr]s are evaluated in order, and the last one is
evaluated in tail position to produce the overall value for the
@scheme[do] form. If no @scheme[finish-expr] is provided, the value of
the @scheme[do] form is @|void-const|.}