Page:Scheme - An interpreter for extended lambda calculus.djvu/8
| Sussman and Steele | December 22, 1975 | 7 | SCHEME Programming Examples |
The semantics of this are that the variables are bound and initialized to the values of the <initi> expressions, which must all be evaluated in the environment outside the DO; then the predicate <pred> is evaluated in the new environment, and if TRUE, the <value> is evaluated and returned. Otherwise the body is evaluated, then each of the steppers <stepi> is evaluated in the current environment, all the variables made to have the results as their values, and the predicate evaluated again, and so on.
For example, the following MacLISP function:
(DEFUN REV (L) (DO ((L1 L (CDR L1)) (ANS NIL (CONS (CAR L1) ANS))) ((NULL L1) ANS)))
computes the reverse of a list. In SCHEME, we could write the same function, in the same iterative style, as follows:
(DEFINE REV (LAMBDA (L) (LABELS ((DOLOOP (LAMBDA (L1 ANS) (IF (NULL L1) ANS (DOLOOP (CDR L1) (CONS (CAR L1) ANS)))))) (DOLOOP L NIL))))
From this we can infer a general way to express iterations in SCHEME in a manner isomorphic to the MacLISP DO:
(LABELS ((DOLOOP (LAMBDA (<dummy> <var1> <var2> ... <varn>) (IF <pred> <value> (DOLOOP <body> <step1> <step2> ... <stepn>))))) (DOLOOP NIL <init1> <init2> ... <initn>))
This is in fact what the supplied DO AMACRO expands into. Note that there are no side effects in the steppings of the iteration variables.
Another Way To Do Recursion [edit]
Now consider the following alternative definition of FACT. It has an extra argument, the continuation [Reynolds], which is a function to call with the answer, when we have it, rather than return a value; that is, rather than ultimately reducing to the desired value, it reduces to a combination which is the application of the continuation to the desired value.