Title: ContinuationPassing Style
1Continuation-Passing Style
- Eric Allen
- Rice University
2What is the meaning of function application?
- ((Eval f env) (Eval a env))
3What is the meaning of function application?
- (Apply-closure (Eval f env) (Eval a env))
4Every specification so far has not explained the
flow of control involved with application
5Other control constructs not explained
- error
- let/cc
- try/catch
- throw
6Solution
- We can rewrite our interpreter to use a highly
restricted form of function application - This restricted form will allow only
- Application of functions to primitive values
- Application of functions to primitive
computations - (must decide what is primitive)
7Example (Before Rewrite)
(define Pi (lambda (l) (cond
((null? l) 1) (else ( (car l) (Pi (cdr
l)))))))
8Rewrite Attempt 1
(define Pi-2 (lambda (l) (local ((define
Pi/acc (lambda (l acc) (cond
((null? l) acc) ((number? (car l))
(Pi/acc (cdr l) ( (car l) acc))) (else
(car l)))))) (Pi/acc l 1)))) To the extend
that this attempt works, it does so
because multiplication is associative.
9Rewrite Attempt 2
(define Pi-3 (lambda (l) (local
((define Pi/acc (lambda (l acc) (cond
((null? l) (acc)) ((number? (car
l)) (Pi/acc (cdr l) (lambda () (
(car l) (acc))))) (else (car l))))))
(Pi/acc l (lambda () 1))))) Problems?
10Rewrite Attempt 3 Continuation-Passing Style
- (define Pi-4
- (lambda (l)
- (local ((define Pi/k
- (lambda (l k)
- (cond
- ((null? l) (k 1))
- ((number? (car l))
- (Pi/k (cdr l) (lambda (rp) (k ( (car l)
rp))))) - (else (car l))))))
- (Pi/k l (lambda (x) x)))))
11How to CPS a Program
- Add an extra parameter to every recursive
function. Call this parameter k.
12How to CPS a Program
- For each applicative clause, pick the application
A that will be evaluated first. Make A the body
for the new clause, but add an extra argument of
the form - (lambda (itrec) body)
- itrec
- input to the rest of the computation
13How to CPS a Program
3. Place the original contents of that clause
inside the extra argument (lambda (itrec)
...),
14How to CPS a Program
- Now every outermost application should be a
primitive expression. - 4. For every outermost primitive expression, wrap
the expression in a call the passed continuation.
15How to CPS a Program
5. Recursively CPS the body of the new
continuation (lambda (itrec) ) Notice
There is no way that a CPS transformation can
escape the body of lambda expression.
16Example on Trees
(define Pi (lambda (t) (cond ((leaf?
t) t) (else ( (Pi (left t)) (Pi
(right t)))))))
17Converted Example
(define Pi/k (lambda (t k) rule 1
(cond ((leaf? t) (k t)) rule 2
(else rule 3 (Pi/k (left t)
(lambda (itrec) ( itrec (Pi (right
t)))))))
But there is still a call to Pi left, which needs
to be converted
18Repeat the Conversion on the Body of the Embedded
Continuation
(define Pi/k (lambda (t k) rule 1
(cond ((leaf? t) (k t)) rule 2
(else rule 3 (Pi/k (left t)
(lambda (itrec) (Pi/k (right t)
(lambda (x) (k
( itrec x))))))))))
19Now We Have Control Over The Flow of Control
- Notice that we made an explicit decision about
the order of evaluation specifically, that the
right child will be traversed before the left. - Other control constructs (errors, try/catch,
etc.) can be modeled by handling the explicit
continuation argument appropriatelly
20CPS and Compilation
- We have motivated CPS as a transformation on the
meta-language of our interpreter - A compiler must perform a CPS (or similar)
transformation to the programs it compiles - CPS style models the control flow in machines we
can physically implement