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 inobjectsare of type continuation.
Calls
combinerin the dynamic environment as a tail context, passing as sole operand to it the continuation to whichcall/ccwould normally return its result. (That is, constructs such a combination and evaluates it in the dynamic environment.)
The
extend-continuationapplicative constructs and returns a new child ofcontinuationthat, when it normally receives a value v, calls the underlying combiner ofapplicativewith 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-guardsandexit-guardsshould 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-continuationconstructs two continuations: a child of continuation, called theouter continuation; and a child of theouter continuation, called theinner continuation. Theinner continuationis returned as the result of the call toguard-continuation.When the
inner continuationnormally receives a value, it passes the value normally to theouter continuation; and when theouter continuationnormally 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
selectorand theinterceptor. Theselectorcontinuation is used in deciding whether to intercept a given abnormal pass, and theinterceptorapplicative 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-guardsandexit-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-continuationconverts 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
eof the dynamic environment is created, containing a binding of<symbol>to the continuation to which the result of the call to$let/ccshould normally return; then, the subexpressions of<objects>are evaluated inefrom 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
combinerin the dynamic extent of the new continuation, with no operands and the dynamic environment of the call toguard-dynamic-extent.
Applicative
exitinitiates an abnormal transfer ofobject(or#inertifobjectwas 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.