#lang scribble/doc @(require "mz.ss") @title[#:tag "cont"]{Continuations} See @secref["cont-model"] and @secref["prompt-model"] for general information about continuations. PLT Scheme's support for prompts and composable continuations most closely resembles Dorai Sitaram's @scheme[%] and @scheme[fcontrol] operator @cite["Sitaram93"]. Scheme installs a @defterm{continuation barrier} around evaluation in the following contexts, preventing full-continuation jumps across the barrier: @itemize[ @item{applying an exception handler, an error escape handler, or an error display handler (see @secref["exns"]);} @item{applying a macro transformer (see @secref["stxtrans"]), evaluating a compile-time expression, or applying a module name resolver (see @secref["modnameresolver"]);} @item{applying a custom-port procedure (see @secref["customport"]), an event guard procedure (see @secref["sync"]), or a parameter guard procedure (see @secref["parameters"]);} @item{applying a security-guard procedure (see @secref["securityguards"]);} @item{applying a will procedure (see @secref["willexecutor"]); or} @item{evaluating or loading code from the stand-alone MzScheme command line (see @secref["running-sa"]).} ] In addition, extensions of PLT Scheme may install barriers in additional contexts. In particular, MrEd installs a continuation barrier around most every callback. Finally, @scheme[call-with-continuation-barrier] applies a thunk barrier between the application and the current continuation. @defproc[(call-with-continuation-prompt [proc procedure?] [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)] [handler (or/c procedure? #f) #f] [arg any/c] ...) any]{ Applies @scheme[proc] to the given @scheme[arg]s with the current continuation extended by a prompt. The prompt is tagged by @scheme[prompt-tag], which must be a result from either @scheme[default-continuation-prompt-tag] (the default) or @scheme[make-continuation-prompt-tag]. The result of @scheme[proc] is the result of the @scheme[call-with-continuation-prompt] call. The @scheme[handler] argument specifies a handler procedure to be called in tail position with respect to the @scheme[call-with-continuation-prompt] call when the installed prompt is the target of a @scheme[abort-current-continuation] call with @scheme[prompt-tag]; the remaining arguments of @scheme[abort-current-continuation] are supplied to the handler procedure. If @scheme[handler] is @scheme[#f], the default handler accepts a single @scheme[_abort-thunk] argument and calls @scheme[(call-with-continuation-prompt _abort-thunk prompt-tag #f)]; that is, the default handler re-installs the prompt and continues with a given thunk.} @defproc[(abort-current-continuation [prompt-tag any/c] [v any/c] ...+) any]{ Resets the current continuation to that of the nearest prompt tagged by @scheme[prompt-tag] in the current continuation; if no such prompt exists, the @exnraise[exn:fail:contract:continuation]. The @scheme[v]s are delivered as arguments to the target prompt's handler procedure. The protocol for @scheme[v]s supplied to an abort is specific to the @scheme[prompt-tag]. When @scheme[abort-current-continuation] is used with @scheme[(default-continuation-prompt-tag)], generally a single thunk should be supplied that is suitable for use with the default prompt handler. Similarly, when @scheme[call-with-continuation-prompt] is used with @scheme[(default-continuation-prompt-tag)], the associated handler should generally accept a single thunk argument.} @defproc*[([(make-continuation-prompt-tag) continuation-prompt-tag?] [(make-continuation-prompt-tag [sym symbol?]) continuation-prompt-tag?])]{ Creates a prompt tag that is not @scheme[equal?] to the result of any other value (including prior or future results from @scheme[make-continuation-prompt-tag]). The optional @scheme[sym] argument, if supplied, is used when printing the prompt tag.} @defproc[(default-continuation-prompt-tag) continuation-prompt-tag?]{ Returns a constant prompt tag for which a prompt is installed at the start of every thread's continuation; the handler for each thread's initial prompt accepts any number of values and returns. The result of @scheme[default-continuation-prompt-tag] is the default tag for more any procedure that accepts a prompt tag.} @defproc[(call-with-current-continuation [proc (continuation? . -> . any)] [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]) any]{ Captures the current continuation up to the nearest prompt tagged by @scheme[prompt-tag]; if no such prompt exists, the @exnraise[exn:fail:contract:continuation]. The truncated continuation includes only continuation marks and @scheme[dynamic-wind] frames installed since the prompt. The capture continuation is delivered to @scheme[proc], which is called in tail position with respect to the @scheme[call-with-current-continuation] call. If the continuation argument to @scheme[proc] is ever applied, then it removes the portion of the current continuation up to the nearest prompt tagged by @scheme[prompt-tag] (not including the prompt; if no such prompt exists, the @exnraise[exn:fail:contract:continuation]), or up to the nearest continuation frame (if any) shared by the current and captured continuations---whichever is first. While removing continuation frames, @scheme[dynamic-wind] @scheme[post-thunk]s are executed. Finally, the (unshared portion of the) captured continuation is appended to the remaining continuation, applying @scheme[dynamic-wind] @scheme[pre-thunk]s. The arguments supplied to an applied procedure become the result values for the restored continuation. In particular, if multiple arguments are supplied, then the continuation receives multiple results. If, at application time, a continuation barrier appears between the current continuation and the prompt tagged with @scheme[prompt-tag], and if the same barrier is not part of the captured continuation, then the @exnraise[exn:fail:contract:continuation]. A continuation can be invoked from the thread (see @secref["threads"]) other than the one where it was captured.} @defproc[(call/cc [proc (continuation? . -> . any)] [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]) any]{ The @scheme[call/cc] binding is an alias for @scheme[call-with-current-continuation]. } @defproc[(call-with-composable-continuation [proc (continuation? . -> . any)] [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]) any]{ Similar to @scheme[call-with-current-continuation], but applying the resulting continuation procedure does not remove any portion of the current continuation. Instead, application always extends the current continuation with the captured continuation (without installing any prompts other than those be captured in the continuation). When @scheme[call-with-composable-continuation] is called, if a continuation barrier appears in the continuation before the closest prompt tagged by @scheme[prompt-tag], the @exnraise[exn:fail:contract:continuation].} @defproc[(call-with-escape-continuation [proc (continuation? . -> . any)]) any]{ Like @scheme[call-with-current-continuation], but @scheme[proc] is not called in tail position, and the continuation procedure supplied to @scheme[proc] can only be called during the dynamic extent of the @scheme[call-with-escape-continuation] call. A continuation barrier, however, never prevents the application of the continuation. Due to the limited applicability of its continuation, @scheme[call-with-escape-continuation] can be implemented more efficiently than @scheme[call-with-current-continuation]. A continuation obtained from @scheme[call-with-escape-continuation] is actually a kind of prompt. Escape continuations are provided mainly for backward compatibility, since they pre-date general prompts in PLT Scheme, and because @scheme[call/ec] is often an easy replacement for @scheme[call/cc] to improve performance.} @defproc[(call/ec [proc (continuation? . -> . any)]) any]{ The @scheme[call/ec] binding is an alias for @scheme[call-with-escape-continuation]. } @defform[(let/cc k body ...+)]{ Equivalent to @scheme[(call/cc (lambda (k) body ...))]. } @defform[(let/ec k body ...+)]{ Equivalent to @scheme[(call/ec (lambda (k) body ...))]. } @defproc[(call-with-continuation-barrier [thunk (-> any)]) any]{ Applies @scheme[thunk] with a barrier between the application and the current continuation. The results of @scheme[thunk] are the results of the @scheme[call-with-continuation-barrier] call.} @defproc[(continuation-prompt-available? [prompt-tag continuation-prompt-tag?] [cont continuation? (call/cc values)]) any]{ Returns @scheme[#t] if @scheme[cont], which must be a continuation, includes a prompt tagged by @scheme[prompt-tag], @scheme[#f] otherwise. } @defproc[(continuation? [v any/c]) boolean?]{ Return @scheme[#t] if @scheme[v] is a continuation as produced by @scheme[call-with-current-continuation], @scheme[call-with-composable-continuation], or @scheme[call-with-escape-continuation], @scheme[#f] otherwise.} @defproc[(continuation-prompt-tag? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v] is a continuation prompt tag as produced by @scheme[default-continuation-prompt-tag] or @scheme[make-continuation-prompt-tag].} @defproc[(dynamic-wind [pre-thunk (-> any)] [value-thunk (-> any)] [post-thunk (-> any)]) any]{ Applies its three thunk arguments in order. The value of a @scheme[dynamic-wind] expression is the value returned by @scheme[value-thunk]. The @scheme[pre-thunk] procedure is invoked before calling @scheme[value-thunk] and @scheme[post-thunk] is invoked after @scheme[value-thunk] returns. The special properties of @scheme[dynamic-wind] are manifest when control jumps into or out of the @scheme[value-thunk] application (either due to a prompt abort or a continuation invocation): every time control jumps into the @scheme[value-thunk] application, @scheme[pre-thunk] is invoked, and every time control jumps out of @scheme[value-thunk], @scheme[post-thunk] is invoked. (No special handling is performed for jumps into or out of the @scheme[pre-thunk] and @scheme[post-thunk] applications.) When @scheme[dynamic-wind] calls @scheme[pre-thunk] for normal evaluation of @scheme[value-thunk], the continuation of the @scheme[pre-thunk] application calls @scheme[value-thunk] (with @scheme[dynamic-wind]'s special jump handling) and then @scheme[post-thunk]. Similarly, the continuation of the @scheme[post-thunk] application returns the value of the preceding @scheme[value-thunk] application to the continuation of the entire @scheme[dynamic-wind] application. When @scheme[pre-thunk] is called due to a continuation jump, the continuation of @scheme[pre-thunk] @itemize[ @item{jumps to a more deeply nested @scheme[pre-thunk], if any, or jumps to the destination continuation; then} @item{continues with the context of the @scheme[pre-thunk]'s @scheme[dynamic-wind] call.} ] Normally, the second part of this continuation is never reached, due to a jump in the first part. However, the second part is relevant because it enables jumps to escape continuations that are contained in the context of the @scheme[dynamic-wind] call. Furthermore, it means that the continuation marks (see @secref["contmarks"]) and parameterization (see @secref["parameters"]) for @scheme[pre-thunk] correspond to those of the @scheme[dynamic-wind] call that installed @scheme[pre-thunk]. The @scheme[pre-thunk] call, however, is @scheme[parameterize-break]ed to disable breaks (see also @secref["breakhandler"]). Similarly, when @scheme[post-thunk] is called due to a continuation jump, the continuation of @scheme[post-thunk] jumps to a less deeply nested @scheme[post-thunk], if any, or jumps to a @scheme[pre-thunk] protecting the destination, if any, or jumps to the destination continuation, then continues from the @scheme[post-thunk]'s @scheme[dynamic-wind] application. As for @scheme[pre-thunk], the parameterization of the original @scheme[dynamic-wind] call is restored for the call, and the call is @scheme[parameterize-break]ed to disable breaks. In both cases, the target for a jump is recomputed after each @scheme[pre-thunk] or @scheme[post-thunk] completes. When a prompt-delimited continuation (see @secref["prompt-model"]) is captured in a @scheme[post-thunk], it might be delimited and instantiated in such a way that the target of a jump turns out to be different when the continuation is applied than when the continuation was captured. There may even be no appropriate target, if a relevant prompt or escape continuation is not in the continuation after the restore; in that case, the first step in a @scheme[pre-thunk] or @scheme[post-thunk]'s continuation can raise an exception. @examples[ (let ([v (let/ec out (dynamic-wind (lambda () (display "in ")) (lambda () (display "pre ") (display (call/cc out)) #f) (lambda () (display "out "))))]) (when v (v "post "))) (let/ec k0 (let/ec k1 (dynamic-wind void (lambda () (k0 'cancel)) (lambda () (k1 'cancel-canceled))))) (let* ([x (make-parameter 0)] [l null] [add (lambda (a b) (set! l (append l (list (cons a b)))))]) (let ([k (parameterize ([x 5]) (dynamic-wind (lambda () (add 1 (x))) (lambda () (parameterize ([x 6]) (let ([k+e (let/cc k (cons k void))]) (add 2 (x)) ((cdr k+e)) (car k+e)))) (lambda () (add 3 (x)))))]) (parameterize ([x 7]) (let/cc esc (k (cons void esc))))) l) ]} @; ---------------------------------------------------------------------- @include-section["control-lib.scrbl"]