[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8 Iteration

Special Form: do ((variable init [step]) …) (test expr …) body …

[R7RS]

  1. Evaluates init … and binds variable … to each result. The following steps are evaluated under the environment where variables are bound.
  2. Evaluate test. If it yields true, evaluates expr … and returns the result(s) of last expr.
  3. Otherwise, evaluates body … for side effects.
  4. Then evaluates step … and binds each result to a fresh variable …, and repeat from the step 2.

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 expression.

Since 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
Special Form: let name ((var init) …) body …

[R7RS] 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 procedures. Some Schemers even prefer named let to do, for the better flexibility.

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 …)
Macro: dotimes ([variable] expr [result]) body …
Macro: dolist ([variable] expr [result]) body …

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 in 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 srfi-42 - Eager comprehensions, which provides rich way to iterate.

Macro: while expr body …
Macro: while expr => var body …
Macro: while expr guard => 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"
Macro: until expr body …
Macro: until expr guard => var body …

Like 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 until, since var would always be bound to #f).

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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated on July 19, 2014 using texi2html 1.82.