Previous: , Up: Control Structures   [Contents][Index]


5.14 Continuations

Whenever a function is called, there is a control path waiting to receive the result of the function, e.g. often the form following the function invocation. This waiting control path is called the continuation of the function, since control will continue down this path when the called function exits.

These continuations are usually not paid much thought, but in some cases it may be useful to be able to directly manipulate the continuation of a function. For this purpose Rep provides the call-with-current-continuation function (often shortened to call/cc) that is standard in Scheme.

Function: call/cc function

function is a function with a single parameter; it will be immediately invoked with this parameter bound to an object representing the current continuation (i.e. the control path that would be taken after function exits).

The continuation object passed to function is itself a function accepting a single argument, when called it transfers control to the continuation of function, as if function had returned the argument applied to the continuation object.

Function: call-with-current-continuation function

This is an alias for call/cc.

In its simplest form, call/cc can mimic the catch and throw procedures (see Catch and Throw), for example:

(defun foo (bar)
  (call/cc (lambda (esc)
             (when (null bar)
               ;; throws out of the call/cc
               (esc nil))
             ;; do something with bar
             …

this is roughly equivalent to:

(defun foo (bar)
  (catch 'tag
    (when (null bar)
      (throw 'tag nil))
    ;; do something with bar
    …

This is only half the story—the most powerful feature of call/cc is that since continuations have dynamic extent (that is, no object is freed until no references to it exist) it is possible to return control to scopes that have already exited.

For example, consider the following fragment of a lisp interaction:

(prog1 (call/cc (lambda (esc)
                  (setq cont esc)))
  (message "foo!"))
    -| foo!
    ⇒ #<closure>

cont
    ⇒ #<closure>

(cont 10)
    -| foo!
    ⇒ 10

The continuation of the prog1 form is saved into the variable cont. When subsequently called with a single argument, it has exactly the same effect as the first time that the second form in the prog1 construct was evaluated.

5.14.1 Implementation Notes

call/cc works by making a copy of the process’ entire call stack. For this reason, it is likely to be less efficient than using the control structures described in the previous parts of this section. Of course, it is much more powerful than the other constructs, so this often outweighs the slight inefficiency.

Also note that currently no attempt is made to save or restore the dynamic state of the Lisp system, apart from variable bindings (both lexical and special). This means that any unwind-protect, condition-case or catch forms that are active when invoking a continuation are all ignored.

Another restriction is that invoking a continuation may not cause control to pass across a dynamic root (see Threads).


Previous: , Up: Control Structures   [Contents][Index]