Next: , Previous: , Up: Control Structures   [Contents][Index]


5.13.3 Looping Structures

Librep only has one method of creating looping control structures—recursion. Any looping construct found in an imperative language can be represented as a recursive function. For example the common while statement:

(while condition body…)
≡
(letrec ((loop (lambda ()
                 (when condition
                   body
                   (loop)))))
  (loop))

Each successive iteration of the loop is simply another call to the function. Also note that the recursive call to the (loop) function occurs in the tail-position of the function. When combined with the system’s ability to eliminate tail-calls (see Function Call Forms) the above example loop has bounded space requirements. This is important when loops make a large number of iterations.

Although tail-recursion is the only primitive method of looping, the language offers a number of looping forms for convenience.

Macro: do vars (test expr…) body…

do is an iteration construct; vars specifies a set of variable bindings to be created, how they are initialized and how they are updated on each iteration. test specifies the termination condition of the loop, any expr… forms are evaluated immediately prior to exiting the ‘do’ construct. The body… forms specify the side effecting body of the loop.

vars is a list of variable clauses, each of which has the structure (variable init step) where variable is the name of a variable, init defines the initial value of its binding, and step defines how the next value of the binding is computed. An alternative form is (variable init), in this case the value of the binding does not change across loop iterations.

Each iteration begins by evaluating test, if the result is false, then the body… expressions are evaluated, and the variables bound to new locations initialized to the results of evaluating the associated step forms.

If the result of evaluating test is true then the expr… forms are evaluated, and the do construct returns the value of the last expr form evaluated.

(do ((vec (make-vector 5))
     (i 0 (1+ i)))
    ((= i 5) vec)
  (aset vec i i))

    ⇒ [0 1 2 3 4]

The “named-let” variant of the let form also provides a convenient looping construct.

Macro: let function bindings body…

This is the same as the (let bindings body…) form described in Local Variables, but within the body… forms, the symbol function is bound to a function whose parameters are the bound variables defined by bindings and whose body is the sequence of forms body

This means that the body of the let may be repeated by invoking the function variable with suitable parameters.

(let loop ((rest '(1 2 3))
           (total 0))
  (if (null rest)
      total
    (loop (cdr rest) (+ total (car rest)))))

    ⇒ 6

Finally, the imperative while form shown at the start of the section is also provided:

Macro: while condition body…

The condition form is evaluated. If it is true an implicit progn is performed on the body forms and the whole procedure is repeated.

This continues until the condition form evaluates to false. The value of every while structure that terminates is false.


Next: , Previous: , Up: Control Structures   [Contents][Index]