10.3 Continuations🔗ℹ

A continuation is a value that encapsulates a piece of an expression’s evaluation context. The call-with-composable-continuation function captures the current continuation starting outside the current function call and running up to the nearest enclosing prompt. (Keep in mind that each REPL interaction is implicitly wrapped in a prompt.)

For example, in

(+ 1 (+ 1 (+ 1 0)))

at the point where 0 is evaluated, the expression context includes three nested addition expressions. We can grab that context by changing 0 to grab the continuation before returning 0:

> (define saved-k #f)
> (define (save-it!)
    (call-with-composable-continuation
     (lambda (k) ; k is the captured continuation
       (set! saved-k k)
       0)))
> (+ 1 (+ 1 (+ 1 (save-it!))))

3

The continuation saved in saved-k encapsulates the program context (+ 1 (+ 1 (+ 1 ?))), where ? represents a place to plug in a result value—because that was the expression context when save-it! was called. The continuation is encapsulated so that it behaves like the function (lambda (v) (+ 1 (+ 1 (+ 1 v)))):

> (saved-k 0)

3

> (saved-k 10)

13

> (saved-k (saved-k 0))

6

The continuation captured by call-with-composable-continuation is determined dynamically, not syntactically. For example, with

> (define (sum n)
    (if (zero? n)
        (save-it!)
        (+ n (sum (sub1 n)))))
> (sum 5)

15

the continuation in saved-k becomes (lambda (x) (+ 5 (+ 4 (+ 3 (+ 2 (+ 1 x)))))):

> (saved-k 0)

15

> (saved-k 10)

25

A more traditional continuation operator in Racket (or Scheme) is call-with-current-continuation, which is usually abbreviated call/cc. It is like call-with-composable-continuation, but applying the captured continuation first aborts (to the current prompt) before restoring the saved continuation. In addition, Scheme systems traditionally support a single prompt at the program start, instead of allowing new prompts via call-with-continuation-prompt. Continuations as in Racket are sometimes called delimited continuations, since a program can introduce new delimiting prompts, and continuations as captured by call-with-composable-continuation are sometimes called composable continuations, because they do not have a built-in abort.

For an example of how continuations are useful, see More: Systems Programming with Racket. For specific control operators that have more convenient names than the primitives described here, see racket/control.