Looping Structures
------------------
The `librep' Lisp dialect 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 (Note: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 variable bindings body...
This is the same as the `(let BINDINGS BODY...)' form described in
Note:Local Variables, but within the BODY... forms, the symbol
VARIABLE 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.