The iteration expressions are: “named
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.
MIT/GNU Scheme permits a variant on the syntax of
let” which provides a more general looping construct
do, and may also be used to express recursions.
let has the same syntax and semantics as ordinary
let except that name is bound within the expressions
to a procedure whose formal arguments are the variables and whose
body is the expressions. Thus the execution of the
expressions may be repeated by invoking the procedure named by
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) …) expression expression …) ((letrec ((name (named-lambda (name variable …) expression expression …))) 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))
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
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
A step may be omitted, in which case the effect is the same as if
(variable init variable) had been written
(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