Iteration (MIT/GNU Scheme 11.0.90)

Next: Structure Definitions, Previous: Sequencing, Up: Special Forms [Contents][Index]

### 2.9 Iteration

The iteration expressions are: “named `let`” and `do`. They are also binding expressions, but are more commonly referred to as iteration expressions. Because Scheme is properly tail-recursive, you don’t need to use these special forms to express iteration; you can simply use appropriately written “recursive” procedure calls.

extended standard special form: let name ((variable init) …) expr expr …

  MIT/GNU Scheme permits a variant on the syntax of `let` called “named `let`” which provides a more general looping construct than `do`, and may also be used to express recursions.

  Named `let` has the same syntax and semantics as ordinary `let` except that name is bound within the exprs to a procedure whose formal arguments are the variables and whose body is the exprs. Thus the execution of the exprs may be repeated by invoking the procedure named by name.

  MIT/GNU Scheme allows any of the inits to be omitted, in which case the corresponding variables are unassigned.

  Note: the following expressions are equivalent:

      (let name ((variable init) …)
        expr
        expr …)

      ((letrec ((name
                 (named-lambda (name variable …)
                   expr
                   expr …)))
         name)
       init …)

  Here is an example:

      (let loop
           ((numbers '(3 -2 1 6 -5))
            (nonneg '())
            (neg '()))
        (cond ((null? numbers)
               (list nonneg neg))
              ((>= (car numbers) 0)
               (loop (cdr numbers)
                     (cons (car numbers) nonneg)
                     neg))
              (else
               (loop (cdr numbers)
                     nonneg
                     (cons (car numbers) neg)))))

           ⇒  ((6 1 3) (-5 -2))

extended standard special form: do ((variable init step) …) (test expression …) command …

  `do` is an iteration construct. It specifies a set of variables to be bound, how they are to be initialized at the start, and how they are to be updated on each iteration. When a termination condition is met, the loop exits with a specified result value.

  `do` expressions are evaluated as follows: The init expressions are evaluated (in some unspecified order), the variables are bound to fresh locations, the results of the init expressions are stored in the bindings of the variables, and then the iteration phase begins.

  Each iteration begins by evaluating test; if the result is false, then the command expressions are evaluated in order for effect, the step expressions are evaluated in some unspecified order, the variables are bound to fresh locations, the results of the steps are stored in the bindings of the variables, and the next iteration begins.

  If test evaluates to a true value, then the expressions are evaluated from left to right and the value of the last expression is returned as the value of the `do` expression. If no expressions are present, then the value of the `do` expression is unspecified in standard Scheme; in MIT/GNU Scheme, the value of test is returned.

  The region of the binding of a variable consists of the entire `do` expression except for the inits. It is an error for a variable to appear more than once in the list of `do` variables.

  A step may be omitted, in which case the effect is the same as if `(variable init variable)` had been written instead of `(variable init)`.

      (do ((vec (make-vector 5))
            (i 0 (+ i 1)))
          ((= i 5) vec)
         (vector-set! vec i i))               ⇒  #(0 1 2 3 4)

      (let ((x '(1 3 5 7 9)))
         (do ((x x (cdr x))
              (sum 0 (+ sum (car x))))
             ((null? x) sum)))                ⇒  25

Next: Structure Definitions, Previous: Sequencing, Up: Special Forms [Contents][Index]