CSE271

CSE271: Principles of Programming Languages

Continuation Passing Style (CPS)

Jooyong Yi (UNIST)

2024 Fall
CSE271

Example: Transforming to CPS

(define fact 
  (lambda (n)
    (if (zero? n)
        1
        (* n (fact (- n 1))))))
2024 Fall
CSE271

Example: Transforming to CPS

(fact 3) = (* 3 (fact 2))
         = (* 3 (* 2 (fact 1)))
         = (* 3 (* 2 (* 1 (fact 0))))
         = (* 3 (* 2 (* 1 1)))
         = (* 3 (* 2 1))
         = (* 3 2)
         = 6
2024 Fall
CSE271

Example: Transforming to CPS

(define fact 
  (lambda (n)
    (if (zero? n)
        1
        (* n (fact (- n 1))))))

(define fact/k 
  (lambda (n cont)
    (if (zero? n)
        ...
2024 Fall
CSE271

Example: Transforming to CPS

(define fact 
  (lambda (n)
    (if (zero? n)
        1
        (* n (fact (- n 1))))))

(define fact/k 
  (lambda (n cont)
    (if (zero? n)
        ...
2024 Fall
CSE271

Example: Transforming to CPS

(define fact 
  (lambda (n)
    (if (zero? n)
        1
        (* n (fact (- n 1))))))

(define fact/k 
  (lambda (n cont)
    (if (zero? n)
        (apply-cont cont 1)
        ...
2024 Fall
CSE271

Example: Transforming to CPS

(define fact 
  (lambda (n)
    (if (zero? n)
        1
        (* n (fact (- n 1))))))

(define fact/k 
  (lambda (n cont)
    (if (zero? n)
        (apply-cont cont 1)
        (fact/k (- n 1) (fact1-cont n cont)))))
2024 Fall
CSE271

Example: Transforming to CPS

(define fact 
  (lambda (n)
    (if (zero? n)
        1
        (* n (fact (- n 1))))))

(define fact 
  (lambda (n) (fact/k n (end-cont))))

(define fact/k
  (lambda (n cont)
    (if (zero? n)
        (apply-cont cont 1)
        (fact/k (- n 1) (fact1-cont n cont)))))
2024 Fall
CSE271

end-cont and fact1-cont

(apply-cont (end-cont) val) = val
(apply-cont (fact1-cont n cont) val) = (apply-cont cont (* n val))
2024 Fall
CSE271

Execution Trace

(fact 3) = (fact/k 3 (end-cont))
(define fact 
  (lambda (n) (fact/k n (end-cont))))
2024 Fall
CSE271

Execution Trace

(fact 3) = (fact/k 3 (end-cont))
         = (fact/k 2 (fact1-cont 3 (end-cont)))
(define fact/k
  (lambda (n cont)
    (if (zero? n)
        (apply-cont cont 1)
        (fact/k (- n 1) (fact1-cont n cont)))))
2024 Fall
CSE271

Execution Trace

(fact 3) = (fact/k 3 (end-cont))
         = (fact/k 2 (fact1-cont 3 (end-cont)))
         = (fact/k 1 (fact1-cont 2 (fact1-cont 3 (end-cont))))
         = (fact/k 0 (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))))         
         = (apply-cont (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))) 1)
(define fact/k
  (lambda (n cont)
    (if (zero? n)
        (apply-cont cont 1)
        (fact/k (- n 1) (fact1-cont n cont)))))
2024 Fall
CSE271

Execution Trace

(fact 3) = ...
         = (fact/k 0 (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))))         
         = (apply-cont (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))) 1)         
         = (apply-cont (fact1-cont 2 (fact1-cont 3 (end-cont))) (* 1 1))
         = (apply-cont (fact1-cont 3 (end-cont)) (* 2 (* 1 1)))
         = (apply-cont (end-cont) (* 3 (* 2 (* 1 1))))
(apply-cont (fact1-cont n cont) val) = (apply-cont cont (* n val))
2024 Fall
CSE271

Execution Trace

(fact 3) = ...
         = (fact/k 0 (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))))         
         = (apply-cont (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))) 1)         
         = (apply-cont (fact1-cont 2 (fact1-cont 3 (end-cont))) (* 1 1))
         = (apply-cont (fact1-cont 3 (end-cont)) (* 2 (* 1 1)))
         = (apply-cont (end-cont) (* 3 (* 2 (* 1 1))))
         = 6
(apply-cont (end-cont) val) = val
2024 Fall
CSE271

Overall Execution Trace

(fact 3) = (fact/k 3 (end-cont))
         = (fact/k 2 (fact1-cont 3 (end-cont)))
         = (fact/k 1 (fact1-cont 2 (fact1-cont 3 (end-cont))))
         = (fact/k 0 (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))))
         = (apply-cont (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))) 1)         
         = (apply-cont (fact1-cont 2 (fact1-cont 3 (end-cont))) (* 1 1))
         = (apply-cont (fact1-cont 3 (end-cont)) (* 2 (* 1 1)))
         = (apply-cont (end-cont) (* 3 (* 2 (* 1 1))))
         = 6
2024 Fall
CSE271

Comparison

(define fact                                       (fact 2) = (* 2 (fact 1))
  (lambda (n)                                               = (* 2 (* 1 (fact 0)))
    (if (zero? n)                                           = (* 2 (* 1 1))
        1                                                   = 2
        (* n (fact (- n 1))))))
(define fact/k                                     (fact/k 2 (end-cont)) 
  (lambda (n cont)                               = (fact/k 1 (fact1-cont 2 (end-cont)))
    (if (zero? n)                                = (fact/k 0 (fact1-cont 1 (fact1-cont 2 (end-cont))))
        (apply-cont cont 1)                      = (apply-cont (fact1-cont 1 (fact1-cont 2 (end-cont))) 1)
        (fact/k (- n 1)                          = (apply-cont (fact1-cont 2 (end-cont)) (* 1 1))                
                (fact1-cont n cont)))))          = (apply-cont (end-cont) (* 2 (* 1 1)))
                                                 = 2       
(apply-cont (end-cont) val) = val
(apply-cont (fact1-cont n cont) val) = (apply-cont cont (* n val))
2024 Fall
CSE271

Implementing Continuations

;; Spec
(apply-cont (end-cont) val) = val
(apply-cont (fact1-cont n cont) val) = (apply-cont cont (* n val))                     
  • Using datatype and pattern matching
(define-datatype continuation continuation?                                            
  (end-cont)
  (fact1-cont 
    (n integer?)
    (cont continuation?)))

(define apply-cont
  (lambda (cont val)
    (cases continuation cont
      (end-cont () val)
      (fact1-cont (saved-n saved-cont)
        (apply-cont saved-cont (* saved-n val))))))
2024 Fall
CSE271

Implementing Continuations

;; Spec
(apply-cont (end-cont) val) = val
(apply-cont (fact1-cont n cont) val) = (apply-cont cont (* n val))                     
  • Using procedural representations
(define apply-cont
  (lambda (cont val) (cont val)))

(define end-cont
  (lambda () (lambda (val) val)))

(define fact1-cont
  (lambda (n cont)
    (lambda (val) (cont (* n val)))))
2024 Fall
CSE271

Execution Trace (Procedure Representation)

(fact 3) = ... = (apply-cont (fact1-cont 1 (fact1-cont 2 (fact1-cont 3 (end-cont)))) 1)
= ((fact1-cont 2 (fact1-cont 3 (end-cont))) (* 1 1))
= ((fact1-cont 3 (end-cont)) (* 2 (* 1 1)))
= ((end-cont) (* 3 (* 2 (* 1 1))))
= 6
(define apply-cont
  (lambda (cont val) (cont val)))

(define end-cont
  (lambda () (lambda (val) val)))

(define fact1-cont
  (lambda (n cont)
    (lambda (val) (cont (* n val)))))
2024 Fall
CSE271

Inlining

(define fact/k                                                                                
  (lambda (n cont)
    (if (zero? n)
        (apply-cont cont 1)
        (fact/k (- n 1)
                (fact1-cont n cont)))))

(define apply-cont                                                                               
  (lambda (cont val) (cont val)))

(define fact/k                                                                               
  (lambda (n cont)
    (if (zero? n)
        (cont 1)
        (fact/k (- n 1)
                (fact1-cont n cont)))))
2024 Fall
CSE271

Inlining

(define fact/k                                                                               
  (lambda (n cont)
    (if (zero? n)
        (cont 1)
        (fact/k (- n 1)
                (fact1-cont n cont)))))

(define fact1-cont                                                                               
  (lambda (n cont)
    (lambda (val) (cont (* n val)))))  

(define fact/k                                                                               
  (lambda (n cont)
    (if (zero? n)
        (cont 1)
        (fact/k (- n 1)
                (lambda (val) (cont (* n val)))))))
2024 Fall
CSE271

Execution Trace (Inlining)

(fact 3) = (fact/k 3 (end-cont))
         = (fact/k 2 (lambda (val) (end-cont (* 3 val))))
         = (fact/k 1 (lambda (val) ((lambda (val) (end-cont (* 3 val))) (* 2 val))))
         = (fact/k 0 (lambda (val) ((lambda (val) ((lambda (val) (end-cont (* 3 val))) (* 2 val))) (* 1 val))))
         = ((lambda (val) 
                    ((lambda (val) 
                             ((lambda (val) 
                                      (end-cont 
                                       (* 3 val))) 
                              (* 2 val))) 
                     (* 1 val)))
            1)
(define fact/k                                                                               
  (lambda (n cont)
    (if (zero? n)
        (cont 1)
        (fact/k (- n 1)
                (lambda (val) (cont (* n val)))))))
2024 Fall
CSE271

Execution Trace (Inlining)

(fact 3) = ...
         = ((lambda (val) 
                    ((lambda (val) 
                             ((lambda (val) 
                                      (end-cont 
                                       (* 3 val))) 
                              (* 2 val))) 
                     (* 1 val)))
            1)
         = ((lambda (val) 
                    ((lambda (val) 
                             (end-cont 
                              (* 3 val))) 
                     (* 2 val)))
            (* 1 1))
2024 Fall
CSE271

Execution Trace (Inlining)

(fact 3) = ...
         = ((lambda (val) 
                    ((lambda (val) 
                             (end-cont 
                              (* 3 val))) 
                     (* 2 val)))
            (* 1 1))
         = ((lambda (val) 
                    (end-cont 
                     (* 3 val)))
            (* 2 (* 1 1)))
2024 Fall
CSE271

Execution Trace (Inlining)

(fact 3) = ...
         = ((lambda (val) 
                    ((lambda (val) 
                             (end-cont 
                              (* 3 val))) 
                     (* 2 val)))
            (* 1 1))
         = ((lambda (val) 
                    (end-cont 
                     (* 3 val)))
            (* 2 (* 1 1)))
         = (end-cont (* 3 (* 2 (* 1 1))))
         = 6
2024 Fall
CSE271

Overall Execution Trace (Inlining)

(fact 3) = ...
         = ((lambda (val) ;; f1
                    ((lambda (val) ;; f2
                             ((lambda (val) ;; f3
                                      (end-cont 
                                       (* 3 val))) 
                              (* 2 val))) 
                     (* 1 val)))
            1)
         = ((lambda (val) 
                    ((lambda (val) 
                             (end-cont 
                              (* 3 val))) 
                     (* 2 val)))
            (* 1 1))
         = ((lambda (val) 
                    (end-cont 
                     (* 3 val)))
            (* 2 (* 1 1)))
         = (end-cont (* 3 (* 2 (* 1 1))))
         = 6
2024 Fall
CSE271

Dataflow through Continuations

(fact 3) = ...                                                                                         
         = ((lambda (val) ;; f1
                    ((lambda (val) ;; f2
                             ((lambda (val) ;; f3
                                      (end-cont 
                                       (* 3 val))) 
                              (* 2 val))) 
                     (* 1 val)))
            1)
         = ((lambda (val) 
                    ((lambda (val) 
                             (end-cont 
                              (* 3 val))) 
                     (* 2 val)))
            (* 1 1))
         = ((lambda (val) 
                    (end-cont 
                     (* 3 val)))
            (* 2 (* 1 1)))
         = (end-cont (* 3 (* 2 (* 1 1))))
         = 6
1 → f1 → f2 → f3 → end-cont → 6
2024 Fall
CSE271
2024 Fall

# Lambda Lifting ```Scheme (define fact/k-helper (lambda (n cont val) (cont (* n val)))) (define fact/k (lambda (n cont) (if (zero? n) (cont 1) (fact/k (- n 1) (lambda (val) (fact/k-helper n cont val)))))) ``` --- ```Scheme (fact 3) = (fact/k 3 (end-cont)) = (fact/k 2 (lambda (val) (fact/k-helper 3 (end-cont) val))) = (fact/k 1 (lambda (val) (fact/k-helper 2 (lambda (val) (fact/k-helper 3 (end-cont) val)) val))) = (fact/k 0 (lambda (val) (fact/k-helper 1 (lambda (val) (fact/k-helper 2 (lambda (val) (fact/k-helper 3 (end-cont) val)) val)) val))) = (fact/k-helper 1 (lambda (val) (fact/k-helper 2 (lambda (val) (fact/k-helper 3 (end-cont) val)) val)) 1) = (fact/k-helper 2 (lambda (val) (fact/k-helper 3 (end-cont) val)) 1) = (fact/k-helper 3 (end-cont) 2) = (end-cont (* 3 2)) = 6 ```