The for family of syntactic forms support iteration over sequences. Lists, vectors, strings, byte strings, input ports, and hash tables can all be used as sequences, and constructors like in-range offer even more kinds of sequences.
(for ([id sequence-expr] )
The for/list variant of for is more Scheme-like. It accumulates body results into a list, instead of evaluating body only for side effects. In more technical terms, for/list implements a list comprehension.
(1 4 9)
(#\a #\b #\c)
The full syntax of for accommodates multiple sequences to iterate in parallel, and the for* variant nests the iterations instead of running them in parallel. More variants of for and for* accumulate body results in different ways. In all of these variants, predicates that prune iterations can be included along with bindings.
Before details on the variations of for, though, it’s best to see the kinds of sequence generators that make interesting examples.
The in-range function generates a sequence of numbers, given an optional starting number (which defaults to 0), a number before which the sequences ends, and an optional step (which defaults to 1).
1 3/2 2 5/2 3 7/2
The in-naturals function is similar, except that the starting number must be an exact non-negative integer (which defaults to 0), the step is always 1, and there is no upper limit. A for loop using just in-naturals will never terminate unless a body expression raises an exception or otherwise escapes.
The stop-before and stop-after functions construct a new sequence given a sequence and a predicate. The new sequence is like the given sequence, but truncated either immediately before or immediately after the first element for which the predicate returns true.
Sequence constructors like in-list, in-vector and in-string simply make explicit the use of a list, vector, or string as a sequence. Since they raise an exception when given the wrong kind of value, and since they otherwise avoid a run-time dispatch to determine the sequence type, they enable more efficient code generation; see Iteration Performance for more information.
in-string: expected argument of type <string>; given (1 2 3)
A more complete syntax of for is
(for (clause )
When multiple [id sequence-expr] clauses are provided in a for form, the corresponding sequences are traversed in parallel:
The #:when boolean-expr form of a clause is another shorthand. It allows the bodys to evaluate only when the boolean-expr produces a true value:
A boolean-expr with #:when can refer to any of the preceding iteration bindings. In a for form, this scoping makes sense only if the test is nested in the iteration of the preceding bindings; thus, bindings separated by #:when are mutually nested, instead of in parallel, even with for.
("1. Intro" "2. Details" "3. Conclusion")
A #:when clause in a for-list form prunes the result list along with evaluations of the bodys:
This pruning behavior of #:when is more useful with for/list than for. Whereas a plain when form normally suffices with for, a when expression form in a for/list would cause the result list to contain #<void>s instead of omitting list elements.
("Guide Intro" "Guide Details" "Ref. Intro" "Ref. Details")
A for*/list form is not quite the same thing as nested for/list forms. Nested for/lists would produce a list of lists, instead of one flattened list. Much like #:when, then, the nesting of for*/list is more useful than the nesting of for*.
The for/first form returns the result of the first time that the bodys are evaluated, skipping further iterations. This form is most useful with a #:when clause.
If the bodys are evaluated zero times, then the result is #f.
The for/last form runs all iterations, returning the value of the last iteration (or #f if no iterations are run):
In the simple case, only one [accum-id init-expr] is provided, and the result of the for/fold is the final value for accum-id, which starts out with the value of init-expr. In the clauses and bodys, accum-id can be referenced to get its current value, and the last body provides the value of accum-id for the next iteration.
When multiple accum-ids are specified, then the last body must produce multiple values, one for each accum-id. The for/fold expression itself produces multiple values for the results.
In the same way that a function or expression can produce multiple values, individual iterations of a sequence can produce multiple elements. For example, a hash table as a sequence generates two values for each iteration: a key and a value.
("banana" "banana" "banana" "apple")
Ideally, a for iteration should run as fast as a loop that you write by hand as a recursive-function invocation. A hand-written loop, however, is normally specific to a particular kind of data, such as lists. In that case, the hand-written loop uses selectors like car and cdr directly, instead of handling all forms of sequences and dispatching to an appropriate iterator.
The for forms can provide the performance of hand-written loops when enough information is apparent about the sequences to iterate. Specifically, the clause should have one of the following fast-clause forms:
[(id id) fast-indexed-seq]
[(id ...) fast-parallel-seq]
(in-range expr expr)
(in-range expr expr expr)
(stop-before fast-seq predicate-expr)
(stop-after fast-seq predicate-expr)
(stop-before fast-indexed-seq predicate-expr)
(stop-after fast-indexed-seq predicate-expr)
(in-parallel fast-seq ...)
(stop-before fast-parallel-seq predicate-expr)
(stop-after fast-parallel-seq predicate-expr)
cpu time: 8 real time: 10 gc time: 0
cpu time: 124 real time: 131 gc time: 0
cpu time: 124 real time: 126 gc time: 0
The grammars above are not complete, because the set of syntactic patterns that provide good performance is extensible, just like the set of sequence values. The documentation for a sequence constructor should indicate the performance benefits of using it directly in a for clause.