Continuations and call/cc
25.1 What Is a Continuation?
At any point in a computation, the continuation is "what remains to be done with the current value". call-with-current-continuation (call/cc) packages the current continuation as a procedure k. Calling (k v) abandons whatever is happening and returns v to that saved point.
(+ 1 (call/cc (lambda (k) 10))) ; 11: k isn't used, the lambda returns normally
(+ 1 (call/cc (lambda (k) (k 41) 1000))) ; 42: calling k jumps out, skipping 1000
(* 2 (call/cc (lambda (k) (+ 100 (k 5))))) ; 10: the pending (+ 100 _) is abandoned25.2 Early Exit
(define (find-first pred lst)
(call/cc
(lambda (return)
(for-each (lambda (x) (when (pred x) (return x))) lst)
#f)))
(find-first negative? '(3 1 -4 1 -5)) ; -4
(define (product lst) ; exit immediately on 0
(call/cc
(lambda (break)
(let loop ((l lst))
(cond ((null? l) 1)
((= (car l) 0) (break 0))
(else (* (car l) (loop (cdr l)))))))))
(product '(1 2 0 4 5)) ; 0, without multiplying the rest25.3 Re-entering Continuations
Re-entry at the REPL behaves differently across implementations, because the "rest of the computation" includes the REPL's own loop. Experiment inside a single procedure to see clean behavior.
(define r #f)
(define count 0)
(define (test)
(let ((v (call/cc (lambda (k) (set! r k) 1))))
(set! count (+ count 1))
(list 'value v 'count count)))
(test) ; (value 1 count 1)
;; Later, re-entering the saved continuation re-runs the rest of TEST's body:
;; (r 5) ; → (value 5 count 2), delivered to wherever (test) was originally called25.4 Continuation-Passing Style (CPS)
Compilers often convert programs to CPS internally. With CPS, call/cc is trivial: it just passes k as a value.
;; Every procedure takes an explicit continuation k: control flow becomes data
(define (fact-cps n k)
(if (= n 0)
(k 1)
(fact-cps (- n 1) (lambda (v) (k (* n v))))))
(fact-cps 5 (lambda (x) x)) ; 120
(define (safe-div-cps a b success failure)
(if (= b 0) (failure "division by zero") (success (/ a b))))
(safe-div-cps 10 2 (lambda (v) (list 'ok v)) (lambda (e) (list 'error e))) ; (ok 5)