6.11.4 Iteration mechanisms

Scheme has only few iteration mechanisms, mainly because iteration in Scheme programs is normally expressed using recursion. Nevertheless, R5RS defines a construct for programming loops, calling `do`. In addition, Guile has an explicit looping syntax called `while`.

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

Bind variables and evaluate body until test is true. The return value is the last expr after test, if given. A simple example will illustrate the basic form,

```(do ((i 1 (1+ i)))
((> i 4))
(display i))
-| 1234
```

Or with two variables and a final return value,

```(do ((i 1 (1+ i))
(p 3 (* 3 p)))
((> i 4)
p)
(format #t "3**~s is ~s\n" i p))
-|
3**1 is 3
3**2 is 9
3**3 is 27
3**4 is 81
⇒
243
```

The variable bindings are established like a `let`, in that the expressions are all evaluated and then all bindings made. When iterating, the optional step expressions are evaluated with the previous bindings in scope, then new bindings all made.

The test expression is a termination condition. Looping stops when the test is true. It’s evaluated before running the body each time, so if it’s true the first time then body is not run at all.

The optional exprs after the test are evaluated at the end of looping, with the final variable bindings available. The last expr gives the return value, or if there are no exprs the return value is unspecified.

Each iteration establishes bindings to fresh locations for the variables, like a new `let` for each iteration. This is done for variables without step expressions too. The following illustrates this, showing how a new `i` is captured by the `lambda` in each iteration (see The Concept of Closure).

```(define lst '())
(do ((i 1 (1+ i)))
((> i 4))
(set! lst (cons (lambda () i) lst)))
(map (lambda (proc) (proc)) lst)
⇒
(4 3 2 1)
```
syntax: while cond body …

Run a loop executing the body forms while cond is true. cond is tested at the start of each iteration, so if it’s `#f` the first time then body is not executed at all.

Within `while`, two extra bindings are provided, they can be used from both cond and body.

Scheme Procedure: break break-arg …

Break out of the `while` form.

Scheme Procedure: continue

Abandon the current iteration, go back to the start and test cond again, etc.

If the loop terminates normally, by the cond evaluating to `#f`, then the `while` expression as a whole evaluates to `#f`. If it terminates by a call to `break` with some number of arguments, those arguments are returned from the `while` expression, as multiple values. Otherwise if it terminates by a call to `break` with no arguments, then return value is `#t`.

```(while #f (error "not reached")) ⇒ #f
(while #t (break)) ⇒ #t
(while #t (break 1 2 3)) ⇒ 1 2 3
```

Each `while` form gets its own `break` and `continue` procedures, operating on that `while`. This means when loops are nested the outer `break` can be used to escape all the way out. For example,

```(while (test1)
(let ((outer-break break))
(while (test2)
(if (something)
(outer-break #f))
...)))
```

Note that each `break` and `continue` procedure can only be used within the dynamic extent of its `while`. Outside the `while` their behaviour is unspecified.

Another very common way of expressing iteration in Scheme programs is the use of the so-called named let.

Named let is a variant of `let` which creates a procedure and calls it in one step. Because of the newly created procedure, named let is more powerful than `do`–it can be used for iteration, but also for arbitrary recursion.

syntax: let variable bindings body

For the definition of bindings see the documentation about `let` (see Local Variable Bindings).

Named `let` works as follows:

• A new procedure which accepts as many arguments as are in bindings is created and bound locally (using `let`) to variable. The new procedure’s formal argument names are the name of the variables.
• The body expressions are inserted into the newly created procedure.
• The procedure is called with the init expressions as the formal arguments.

The next example implements a loop which iterates (by recursion) 1000 times.

```(let lp ((x 1000))
(if (positive? x)
(lp (- x 1))
x))
⇒
0
```