Steele and Sussman | March 10, 1976 | 14 | LAMBDA: The Ultimate Imperative |
(LABELS ((HARMSUM
(LAMBDA (A N ESCFUN)
(LABELS ((LOOP
(LAMBDA (1 SUM)
(IF (= I N) SUM
(IF (= (A I) 0) (ESCFUN 0)
(LOOP (+ I 1)
(+ SUM (/ 1 (A I)))))))))
(LOOP 0 0)))))
(BLOCK (ARRAY B 100)
(PRINT (CATCH X (/ 100 (HARMSUM B 100 X))))))
This actually works, but elucidates very little about the nature of ESCAPE
. We can eliminate the use of CATCH
by using continuation-passing. Let us do for HARMSUM
what we did earlier for FACT
. Let it take an extra argument C
, which is called as a function on the result.
(LABELS ((HARMSUM
(LAMBDA (A N ESCFUN C)
(LABELS ((LOOP
(LAMBDA (I SUM)
(IF (= I N) (C SUM)
(IF (= (A I) 0) (ESCFUN 0)
(LOOP (+ I 1)
(+ SUM (/ 1 (A I)))))))))
(LOOP 0 0)))))
(BLOCK (ARRAY B 100)
(LABELS ((AFTER-THE-CATCH
(LAMBDA (Z) (PRINT Z))))
(HARMSUM B
100
AFTER-THE-CATCH
(LAMBDA (Y) (AFTER-THE-CATCH (/ 100 Y)))))))
Notice that if we use ESCFUN
, then C
does not get called. In this way the division is avoided. This example shows how ESCFUN
may be considered to be an "alternate continuation".
Dynamic Variable Scoping
In this section we will consider the problem of dynamically scoped, or "fluid", variables. These do not exist in ALGOL, but are typical of many LISP implementations, ECL, and APL. We will see that fluid variables may be modelled in more than one way, and that one of these is closely related to continuation-passing.