Iterate and reduce are extensions of named-let for
 writing loops that walk down one or more sequences,
 such as the elements of a list or vector, the
 characters read from a port, or an arithmetic series.
Additional sequences can be defined by the user.
Iterate and reduce are in structure reduce.
The syntax of iterate is:
(iterateloop-name((sequence-typeelement-variablesequence-data...) ...) ((state-variableinitial-value) ...)body-expression[final-expression])
Iterate steps the element-variables in parallel through the
 sequences, while each state-variable has the corresponding
 initial-value for the first iteration and have later values
 supplied by body-expression. 
If any sequence has reached its limit the value of the iterate
 expression is
 the value of final-expression, if present, or the current values of
 the state-variables, returned as multiple values.
If no sequence has reached
 its limit, body-expression is evaluated and either calls loop-name with
 new values for the state-variables, or returns some other value(s).
The loop-name and the state-variables and initial-values behave
exactly as in named-let.  The named-let expression
  (let loop-name ((state-variable initial-value) ...)
    body ...)
iterate expression with no sequences
 (and with an explicit
 let wrapped around the body expressions to take care of any
 internal defines):
  (iterate loop-name
           ()
           ((state-variable initial-value) ...)
    (let () body ...))
The sequence-types are keywords (they are actually macros of a particular
 form; it is easy to add additional types of sequences).
Examples are list* which walks down the elements of a list and
 vector* which does the same for vectors.
For each iteration, each element-variable is bound to the next
 element of the sequence.
The sequence-data gives the actual list or vector or whatever.
If there is a final-expression, it is evaluated when the end of one or more
 sequences is reached.
If the body-expression does not call loop-name the
 final-expression is not evaluated.
The state-variables are visible in
 final-expression but the sequence-variables are not.  
The body-expression and the final-expression are in tail-position within
 the iterate.
Unlike named-let, the behavior of a non-tail-recursive call to
 loop-name is unspecified (because iterating down a sequence may involve side
 effects, such as reading characters from a port).
If an iterate expression is not meant to terminate before a sequence
 has reached its end,
 body-expression will always end with a tail call to loop-name.
Reduce is a macro that makes this common case explicit.
The syntax of reduce is
 the same as that of iterate, except that there is no loop-name.
The body-expression returns new values of the state-variables
 instead of passing them to loop-name.
Thus body-expression must return as many values as there are state
 variables.
By special dispensation, if there are
 no state variables then body-expression may return any number of values,
 all of which are ignored.
The syntax of reduce is:
(reduce ((sequence-typeelement-variablesequence-data...) ...) ((state-variableinitial-value) ...)body-expression[final-expression])
The value(s) returned by an instance of reduce is the value(s) returned
 by the final-expression, if present, or the current value(s) of the state
variables when the end of one or more sequences is reached.
A reduce expression can be rewritten as an equivalent iterate
 expression by adding a loop-var and a wrapper for the
 body-expression that calls the loop-var.
(iterate loop
         ((sequence-type element-variable sequence-data ...)
          ...)
         ((state-variable initial-value)
          ...)
  (call-with-values (lambda ()
                      body-expression)
                    loop)
  [final-expression])
The predefined sequence types are:
| (list*  | syntax | 
| (vector*  | syntax | 
| (string*  | syntax | 
| (count*  | syntax | 
| (input*  | syntax | 
| (stream*  | syntax | 
For lists, vectors, and strings the element variable is bound to the successive elements of the list or vector, or the characters in the string.
For count* the element variable is bound to the elements of the sequence
inclusive ofstart,start+step,start+ 2step, ...,end
start and exclusive of end.
The default step is 1.
The sequence does not terminate if no end is given or if there
 is no N > 0 such that end = start + Nstep
 (= is used to test for termination).
For example, (count* i 0 -1) doesn't terminate
 because it begins past the end value and (count* i 0 1 2) doesn't
 terminate because it skips over the end value.
For input* the elements are the results of successive applications
 of read-procedure to input-port.
The sequence ends when read-procedure returns an end-of-file object.
For a stream, the procedure takes the current data value as an argument
 and returns two values, the next value of the sequence and a new data value.
If the new data is #f then the previous element was the last
 one.  For example,
is the same as(list* elt my-list)
where(stream* elt list->stream my-list)
list->stream is
  (lambda (list)
    (if (null? list)
        (values 'ignored #f)
        (values (car list) (cdr list))))
When using the sequence types described above, a loop terminates when any of its sequences reaches its end. To help detect bugs it is useful to have sequence types that check to see if two or more sequences end on the same iteration. For this purpose there is second set of sequence types called synchronous sequences. These are identical to the ones listed above except that they cause an error to be signalled if a loop is terminated by a synchronous sequence and some other synchronous sequence did not reach its end on the same iteration.
Sequences are checked for termination in order, from left to right, and if a loop is terminated by a non-synchronous sequence no further checking is done.
The synchronous sequences are:
| (list%  | syntax | 
| (vector%  | syntax | 
| (string%  | syntax | 
| (count%  | syntax | 
| (input%  | syntax | 
| (stream%  | syntax | 
Note that the synchronous count% must have an end, unlike the
 nonsynchronous count%.
Gathering the indexes of list elements that answer true to some predicate.
(lambda (my-list predicate)
  (reduce ((list* elt my-list)
           (count* i 0))
          ((hits '()))
    (if (predicate elt)
        (cons i hits)
        hits)
    (reverse hits))
Looking for the index of an element of a list.
(lambda (my-list predicate)
  (iterate loop
           ((list* elt my-list)
            (count* i 0))
           ()                                ; no state
    (if (predicate elt)
        i
        (loop))))
Reading one line.
(define (read-line port)
  (iterate loop
           ((input* c port read-char))
           ((chars '()))
    (if (char=? c #\newline)
        (list->string (reverse chars))
        (loop (cons c chars)))
    (if (null? chars)
        (eof-object)
        ; no newline at end of file
        (list->string (reverse chars)))))
Counting the lines in a file.  We can't use count* because we
need the value of the count after the loop has finished.
(define (line-count name)
  (call-with-input-file name
    (lambda (in)
      (reduce ((input* l in read-line))
              ((i 0))
        (+ i 1)))))
The sequence types are object-oriented macros similar to enumerations.
A non-synchronous sequence macro needs to supply three values:
 #f to indicate that it isn't synchronous, a list of state variables
 and their initializers, and the code for one iteration.
The first
 two methods are CPS'ed: they take another macro and argument to
 which to pass their result.
The synchronized? method gets no additional arguments.
The state-vars method is passed a list of names which
 will be bound to the arguments to the sequence.
The final method, for the step, is passed the list of names bound to
 the arguments and the list of state variables.
In addition there is
 a variable to be bound to the next element of the sequence, the
 body expression for the loop, and an expression for terminating the
 loop.
The definition of list* is
(define-syntax list*
  (syntax-rules (synchronized? state-vars step)
    ((list* synchronized? (next more))
     (next #f more))
    ((list* state-vars (start-list) (next more))
     (next ((list-var start-list)) more))
    ((list* step (start-list) (list-var)
            value-var loop-body final-exp)
     (if (null? list-var)
         final-exp
         (let ((value-var (car list-var))
               (list-var (cdr list-var)))
           loop-body)))))
Synchronized sequences are the same, except that they need to provide a termination test to be used when some other synchronized method terminates the loop.
(define-syntax list%
  (syntax-rules (sync done)
    ((list% sync (next more))
     (next #t more))
    ((list% done (start-list) (list-var))
     (null? list-var))
    ((list% stuff ...)
     (list* stuff ...))))
The expansion of
  (reduce ((list* x '(1 2 3)))
          ((r '()))
    (cons x r))
  (let ((final (lambda (r) (values r)))
        (list '(1 2 3))
        (r '()))
    (let loop ((list list) (r r))
      (if (null? list)
          (final r)
          (let ((x (car list))
                (list (cdr list)))
            (let ((continue (lambda (r)
                              (loop list r))))
              (continue (cons x r)))))))
The only inefficiencies in this code are the final and continue
 procedures, both of which could be substituted in-line.
The macro expander could do the substitution for continue when there
 is no explicit proceed variable, as in this case, but not in general.
Previous: Macros for writing loops | Next: Macros for writing loops