The following example loops 10 times while accumulating each value of i to j and returns it.
(do ((i 0 (+ i 1)) (j 0 (+ i j))) ((= i 10) j) (print j)) ⇒ 45 ; also prints intermediate values of j
If step is omitted, the previous value of variable
is carried over. When there’s no expr, the non-false
value returned by test becomes the value of the
do syntax uses many parentheses, some prefer using
square brackets as well as parentheses to visually distinguish
the groupings. A common way is to group each variable binding,
and the test clause, by square brackets.
(do ([i 0 (+ i 1)] [j 0 (+ i j)]) [(= i 10) j] (print j))
Note: Unlike Common Lisp (and “for loops” in many languages), variable is freshly bound for each iteration. The following example loops 5 times and creates a list of closures, each of which closes the variable i. When you call each closures, you can see that each of them closes different i at the time of the iteration they were created.
(define closures (do ([i 0 (+ i 1)] [c '() (cons (^ i) c)]) [(= i 5) (reverse c)] )) ((car closures)) ⇒ 0 ((cadr closures)) ⇒ 1
This variation of
let is called “named let”. It creates
the following procedure and binds it to name, then calls
it with init ….
(lambda (var …) body …)
This syntax itself isn’t necessarily related to iteration. However, the whole point of named let is that the above lambda expression is within the scope of name—that is, you can call name recursively within body. Hence this is used very often to write a loop by recursion (thus, often the procedure is named loop, as in the following example.)
(let loop ([x 0] [y '()]) (if (= x 10) y (loop (+ x 1) (cons x y)))) ⇒ (9 8 7 6 5 4 3 2 1 0)
Of course you don’t need to loop with a named let; you can call name
in non-tail position, pass name to other higher-order procedure, etc.
Named let exists since it captures a very common pattern of local recursive
Some Schemers even prefer named let to
do, for the better
The following rewrite rule precisely explains the named let semantics.
The tricky use of
letrec in the expansion is to make
proc visible from body … but not from init ….
(let proc ((var init) …) body …) ≡ ((letrec ((proc (lambda (var …) body …))) proc) init …)
Imported from Common Lisp. The full form are expanded as follows:
(dotimes (variable expr result) body …) ≡ (do ((limit expr) (variable 0 (+ variable 1))) ((>= variable expr) result) body …) (dolist (variable expr result) body …) ≡ (begin (for-each (lambda (variable) body …) expr) (let ((variable '())) result))
(The reason we bind variable to
() to evaluate result
dolist is the CL compatibility.)
You can omit result, or both result and variable. That is, if the first argument has two elements, they’re variable and expr. In which case, the result of these forms is undefined.
If both result and variable are omitted, these forms just repeatedly executes body … number of times determined by expr.
;; print "a" 10 times. (dotimes (10) (print "a")) ;; print "a" (length lst) times. (dolist (lst) (print "a"))
See also Eager comprehensions, which provides rich way to iterate.
=>var body …
=>var body …
Var is an identifier and guard is a procedure that takes one argument.
In the first form, expr is evaluated, and if it yields a true value, body … are evaluated. It is repeated while expr yields true value.
In the second form, var is bound to a result of expr in the scope of body ….
In the third form, the value expr yields are passed to guard, and the execution of body … is repeated while guard returns a true value. var is bound to the result of expr.
The return value of
while form itself isn’t specified.
(let ((a '(0 1 2 3 4))) (while (pair? a) (write (pop! a)))) ⇒ prints "01234" (let ((a '(0 1 2 3 #f 5 6))) (while (pop! a) integer? => var (write var))) ⇒ prints "0123"
=>var body …
while, but the condition is reversed. That is,
the first form repeats evaluation of expr and body …
until expr yields true. In the second form,
the result of expr is passed to guard, and the
execution is repeated until it returns true. Var is bound
to the result of expr.
(The second form without guard isn’t useful in
var would always be bound to
The return value of
until form itself isn’t specified.
(let ((a '(0 1 2 3 4))) (until (null? a) (write (pop! a)))) ⇒ prints "01234" (until (read-char) eof-object? => ch (write-char ch)) ⇒ reads from stdin and writes char until EOF is read