10 Continuations
A continuation is a plan for all future computation, parameterized by a value to be provided, and contingent on the states of all mutable data structures (which notably may include environments). When the Kernel evaluator is invoked, the invoker provides a continuation to which the result of the evaluation will normally be returned.
For example, when $if
evaluates its test operand, the continuation provided for the result expects to be given a boolean value; and, depending on which boolean it gets, it will evaluate either the consequent or the alternative operand as a tail context — that is, the continuation provided for the result of evaluating the selected operand is the same continuation that was provided for the result of the call to $if
.
A Kernel program may sometimes capture a continuation; that is, acquire a reference to it as a first-class object. The basic means of continuation capture is applicative call/cc
. Given a first-class continuation c
, a combiner can be constructed that will abnormally pass its operand tree to c
(as opposed to the normal return of values to continuations). In the simplest case, the abnormally passed value arrives at c
as if it had been normally returned to c
. In general, continuations bypassed by the abnormal pass may have entry/exit guards attached to them, and these guards can intercept the abnormal pass before it reaches c
. Each entry/exit guard consists of a selector continuation, which designates which abnormal passes the guard will intercept, and an interceptor applicative that performs the interception when selected.
Continuations are immutable, and are equal?
iff eq?
. The continuation type is encapsulated.
The primitive type predicate for type continuation.
continuation?
returns true iff all the objects inobjects
are of type continuation.
Calls
combiner
in the dynamic environment as a tail context, passing as sole operand to it the continuation to whichcall/cc
would normally return its result. (That is, constructs such a combination and evaluates it in the dynamic environment.)
The
extend-continuation
applicative constructs and returns a new child ofcontinuation
that, when it normally receives a value v, calls the underlying combiner ofapplicative
with dynamic environmentenvironment
(or an empty environment if none was specified) and operand treev
, the result of the call normally to be returned tocontinuation
.The following equivalnece defines the short version:
(extend-continuation c a) == (extend-continuation c a (make-environment))
entry-guards
andexit-guards
should each be a list of clauses; each clause should be a list of length two, whose first element is a continuation, and whose second element is an applicative whose underlying combiner is operative.Applicative
guard-continuation
constructs two continuations: a child of continuation, called theouter continuation
; and a child of theouter continuation
, called theinner continuation
. Theinner continuation
is returned as the result of the call toguard-continuation
.When the
inner continuation
normally receives a value, it passes the value normally to theouter continuation
; and when theouter continuation
normally receives a value, it passes the value normally tocontinuation
. Thus, in the absence of abnormal passing, the inner and outer continuations each have the same behavior ascontinuation
.The two elements of each guard clause are called, respectively, the
selector
and theinterceptor
. Theselector
continuation is used in deciding whether to intercept a given abnormal pass, and theinterceptor
applicative is called to perform customized action when interception occurs.At the beginning of the call to
guard-continuation
, internal copies are made of the evaluation structures ofentry-guards
andexit-guards
, so that the selectors and interceptors contained in the arguments at that time remain fixed thereafter, independent of any subsequent mutations to the arguments.
Returns an applicative whose underlying operative abnormally passes its operand tree to
continuation
, thus: A series of interceptors are selected to handle the abnormal pass, and a continuation is derived that will normally perform all the interceptions in sequence and pass some value to the destination of the originally abnormal pass. The operand tree is then normally passed to the derived continuation.
This continuation is the ancestor of all other continuations. When it normally receives a value, it terminates the Kernel session. (For example, if the system is running a read-eval-print loop, it exits the loop.)
The dynamic extent of this continuation is mutually disjoint from the dynamic extent in which Kernel computation usually occurs (such as the dynamic extent in which the Kernel system would run a read-eval-print loop).
When this continuation normally receives a value, it provides a diagnostic message to the user of the Kernel system, on the assumption that the received value is an attempt to describe some error that aborted a computation; and then resumes operation of the Kernel system at some point that is outside of all user-defined computation. (For example, if the system is running a read-eval-print loop, operation may resume by continuing from the top of the loop.)
The diagnostic message is not made available to any Kernel computation, and is therefore permitted to contain information that violates abstractions within the system.
When an error is signaled during a Kernel computation, the signaling action consists of an abnormal pass to some continuation in the dynamic extent of
error-continuation
.
Applicative
apply-continuation
converts its first argument to an applicative as if bycontinuation->applicative
, and then applies it as usual.That is:
(apply-continuation continuation object) == (apply (continuation->applicative continuation) object)
A child environment
e
of the dynamic environment is created, containing a binding of<symbol>
to the continuation to which the result of the call to$let/cc
should normally return; then, the subexpressions of<objects>
are evaluated ine
from left to right, with the last (if any) evaluated as a tail context, or if<objects>
is empty the result is inert.That is:
($let/cc symbol . objects) == (call/cc ($lambda (symbol) . objects))
This applicative extends the current continuation with the specified guards, and calls
combiner
in the dynamic extent of the new continuation, with no operands and the dynamic environment of the call toguard-dynamic-extent
.
Applicative
exit
initiates an abnormal transfer ofobject
(or#inert
ifobject
was not specified), toroot-continuation
. That is:(exit) == (apply-continuation root-continuation #inert) (exit obj) == (apply-continuation root-continuation obj)SOURCE NOTE: This applicative doesn’t have the optional argument in the report. It was added to klisp to allow a simple way to terminate the interpreter passing a value that is then tried to convert to an exit status.