Next: Quasiquotation, Previous: Grouping, Up: Core syntax [Contents][Index]
[R7RS base]
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
[R7RS base]
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 …)
Convenience loop syntaxes, imported from Common Lisp. They are not very Scheme-y, in a sense that these rely on some side-effects in body …. Nevertheless these capture some common pattern in day-to-day scripting.
You can use dotimes
to repeat body … for a number
of times given by num-expr,
and dolist
to repeat body …
while traversing a list given by list-expr. While body …
is evaluated,
variable is bound to the current iteration count (in dotimes
),
or the current element in the list (in dolist
).
(dotimes (n 5) (write n)) ⇒ writes "01234" (dolist (v '(a b c d e)) (write v)) ⇒ writes "abcde"
If you don’t need to refer to variable, you can omit it.
For example, the following example prints year!
10 times:
(dotimes (10) (print "yeah!"))
If the third element (result) is given in dotimes
or
dolist
, it is evaluated after all repetition is done, and its result
becomes the result of dotimes
/dolist
. While result
is evaluated, variable is bound to the number of repetitions
(in dotimes
) or ()
(in dolist
).
It is supported because Common Lisp has it.
Note that a fresh variable is bound for each iteration, as opposed to Common Lisp where variable is mutated. So if you create a closure closing variable, it won’t be overwritten by the subsequent iteration.
If you need more than simple iteration, you can use do
form,
named let
, or srfi.42
- 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 … ¶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
Next: Quasiquotation, Previous: Grouping, Up: Core syntax [Contents][Index]