20-CS-4003-001 Organization of Programming Languages Fall 2017
Call-with-current-continuation examples

Lambda calculus, Type theory, Formal semantics, Program analysis

    Prev     Next     All lectures        Code

Escaping to avoid computation

(define call/cc call-with-current-continuation)

;; Simple multiply - wasteful if 0 is present in the
;; list (all multiplies are done)
(define mul
  (lambda (l)
    (if (null? l)
        1
        (* (car l) (mul (cdr l))))))

;; Multiply in continuation passing style - the last
;; line in mul^ passes and continues to build the needed
;; continuation - all multiplies are still done.
(define mul^
  (lambda (l f)
    (if (null? l)
        (f)
        (mul^ (cdr l) (lambda () (* (car l) (f)))))))

(define one (lambda () 1))

;; Multiply in continuation passing style - the last
;; line in mul^^ passes and continues to build the
;; needed continuation - this is different from the
;; solution above in that the line (zero? (car l)) is
;; added to test for the escape.  However this line
;; could not be added directly to mul^^ because some
;; multiplies would occur in that case upon escape.
;; Splitting the computation into two separate functions,
;; times and mul^^, and putting the escape test in times,
;; allows the computation to return immediately from
;; times when escaping.
(define times
  (lambda (l f)
    (if (null? l)
        (f)
        (if (zero? (car  l))
            0
            (mul^^ l f)))))

(define mul^^
  (lambda (l f)
    (times (cdr l) (lambda () (* (car l) (f))))))

;; Use of call/cc to escape without multiplying in
;; case there is a 0 factor
(define m
  (lambda (l)
    (let ((k (call/cc (lambda (h) h))))
      (if (number? k)
          0
          (mul* l k)))))

(define mul*
  (lambda (l k)
    (if (null? l)
        1
        (if (zero? (car l))
            (k 0)
            (* (car l) (mul* (cdr l) k))))))
 -  These are examples of how continuations are used to escape from deep within a procedure. The problem is to avoid extra computation while coming out of a stack of procedures. In "C" this problem is solved easily with a goto. But there is no real goto in Scheme and Scheme solutions are typically recursive so something extra has to be done. A solution is to progressively build a continuation (the future of a computation) around until it is realized that no escape is possible and then invoke the continuation to get the result; in the case of escape, the continuation is discarded. The examples to the left apply to multiplication of a list of integers. If one integer in the list is 0 then the computation should immediately terminate (escape) without multiplying anything. The first example shows a typical multiply without any escape mechanism. In the second example, it is shown how to build the needed continuation. In the third example the escape mechanism is added. In the fourth example it is shown how to achieve the same effect with call-with-current-continuation. An example, not shown here, is finding the greatest common divisor of a list of integers.