To CPS-convert a cond statement:
If the questions are all tail calls, send the answer of each cond-clause to the continuation k, then check whether the new answer expressions have any tail calls. Convert as needed.
If a question has a non-tail call, pull the call outside the cond and replace the question with the box (the arg to the lambda). Then continue the conversion as before.
(define (rect-area w h) (* w h)) (+ (rect-area 10 8) 3) ==> (define (rect-area/k w h k) (k (* w h))) (rect-area/k 10 8 (lambda (v) (+ v 3)))
(define (g x) (* x 6)) (define (h y) (+ y 5)) (+ 4 (g (h 3))) [hint: convert to using h/k and g first, then to h/k and g/k] ==> (define (g/k x k) (k (* x 6))) (define (h/k y k) (k (+ y 5))) (h/k 3 (lambda (v1) (+ 4 (g v1)))) ==> (h/k 3 (lambda (v1) (g/k v1 (lambda (v2) (+ 4 v2)))))
(define (foo y) (+ (h (* y 2)) 7)) [h from above] (foo 8) ==> (define (foo/k y k) (k (+ (h (* y 2)) 7))) [h from above] ==> (define (foo/k y k) (h/k (* y 2) (lambda (v) (k (+ v 7))))) (foo/k 8 (lambda (x) x))
(define (sum-area w1 h1 w2 h2) (+ (rect-area w1 h1) (rect-area w2 h2))) (sum-area 2 4 6 8) ==> (define (sum-area/k w1 h1 w2 h2 k) (rect-area/k w1 w2 (lambda (vleft) (k (+ vleft (rect-area w2 h2)))))) ==> (define (sum-area/k w1 h1 w2 h2 k) (rect-area/k w1 h1 (lambda (vleft) (rect-area/k w2 h2 (lambda (vright) (k (+ vleft vright))))))) (sum-area 2 4 6 8 (lambda (x) x)) [note that we have "linearized" the "tree-like" calls to rect-area]
(define (product alon) (cond [(empty? alon) 1] [(cons? alon) (* (first alon) (product (rest alon)))])) ==> [send both answers to k] (define (product/k alon k) (cond [(empty? alon) (k 1)] [(cons? alon) (k (* (first alon) (product (rest alon))))])) ==> [convert the non-tail call in the cons? answer] (define (product/k alon k) (cond [(empty? alon) (k 1)] [(cons? alon) (product/k (rest alon) (lambda (box) (k (* (first alon) box))))]))
(define (filter pred L) (cond [(empty? L) empty] [(cons? L) (cond [(pred (first L)) (cons (first L) (filter pred (rest L)))] [else (filter pred (rest L))])])) ==> [send both answers to k] (define (filter/k pred L k) (cond [(empty? L) (k empty)] [(cons? L) (k (cond [(pred (first L)) (cons (first L) (filter pred (rest L)))] [else (filter pred (rest L))])]))) ==> [pull up the non-tail call in the question (pred (first L))] (define (filter/k pred/k L k) (cond [(empty? L) (k empty)] [(cons? L) (pred/k (first L) (lambda (predval) (k (cond [predval (cons (first L) (filter pred (rest L)))] [else (filter pred (rest L))]))))])) ==> [send both answers of hte inner cond to k] (define (filter/k pred/k L k) (cond [(empty? L) (k empty)] [(cons? L) (pred/k (first L) (lambda (predval) (cond [predval (k (cons (first L) (filter pred (rest L))))] [else (k (filter pred (rest L)))])))])) ==> [work the k into both answer expressions] (define (filter/k pred/k L k) (cond [(empty? L) (k empty)] [(cons? L) (pred/k (first L) (lambda (predval) (cond [predval (filter/k pred/k (rest L) (lambda (box) (k (cons (first L) box))))] [else (k (filter pred (rest L)))])))])) ==> (define (filter/k pred/k L k) (cond [(empty? L) (k empty)] [(cons? L) (pred/k (first L) (lambda (predval) (cond [predval (filter/k pred/k (rest L) (lambda (box) (k (cons (first L) box))))] [else (filter/k pred/k (rest L) k)])))]))
This page maintained by Kathi Fisler Department of Computer Science Worcester Polytechnic Institute |