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
(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
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.
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
(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
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.
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
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:
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