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 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.
This is an alias for
In its simplest form,
call/cc can mimic the
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.
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
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).