1#lang scribble/doc 2@(require "mz.rkt") 3 4@title[#:tag "cont"]{Continuations} 5 6@guideintro["conts"]{continuations} 7 8See @secref["cont-model"] and @secref["prompt-model"] for general 9information about continuations. Racket's support for prompts and 10composable continuations most closely resembles Dorai Sitaram's 11@racket[%] and @racket[fcontrol] operator @cite["Sitaram93"]. 12 13Racket installs a @tech{continuation barrier} around evaluation in the 14following contexts, preventing full-continuation jumps into the 15evaluation context protected by the barrier: 16 17@itemize[ 18 19 @item{applying an exception handler, an error escape handler, or an 20 error display handler (see @secref["exns"]);} 21 22 @item{applying a macro transformer (see @secref["stxtrans"]), 23 evaluating a compile-time expression, or applying a module name 24 resolver (see @secref["modnameresolver"]);} 25 26 @item{applying a custom-port procedure (see @secref["customport"]), an 27 event guard procedure (see @secref["sync"]), or a parameter guard 28 procedure (see @secref["parameters"]);} 29 30 @item{applying a security-guard procedure (see 31 @secref["securityguards"]);} 32 33 @item{applying a will procedure (see @secref["willexecutor"]); or} 34 35 @item{evaluating or loading code from the stand-alone Racket 36 command line (see @secref["running-sa"]).} 37 38] 39 40In addition, extensions of Racket may install barriers in 41additional contexts. Finally, 42@racket[call-with-continuation-barrier] applies a thunk barrier 43between the application and the current continuation. 44 45 46@defproc[(call-with-continuation-prompt 47 [proc procedure?] 48 [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)] 49 [handler (or/c procedure? #f) #f] 50 [arg any/c] ...) 51 any]{ 52 53Applies @racket[proc] to the given @racket[arg]s with the current 54continuation extended by a prompt. The prompt is tagged by 55@racket[prompt-tag], which must be a result from either 56@racket[default-continuation-prompt-tag] (the default) or 57@racket[make-continuation-prompt-tag]. The call to 58@racket[call-with-continuation-prompt] returns the result of 59@racket[proc]. 60 61The @racket[handler] argument specifies a handler procedure to be 62called in tail position with respect to the 63@racket[call-with-continuation-prompt] call when the installed prompt 64is the target of an @racket[abort-current-continuation] call with 65@racket[prompt-tag]; the remaining arguments of 66@racket[abort-current-continuation] are supplied to the handler 67procedure. If @racket[handler] is @racket[#f], the default handler 68accepts a single @racket[_abort-thunk] argument and calls 69@racket[(call-with-continuation-prompt _abort-thunk prompt-tag #f)]; 70that is, the default handler re-installs the prompt and continues with 71a given thunk.} 72 73@defproc[(abort-current-continuation 74 [prompt-tag any/c] 75 [v any/c] ...) 76 any]{ 77 78Resets the current continuation to that of the nearest prompt tagged 79by @racket[prompt-tag] in the current continuation; if no such prompt exists, 80the @exnraise[exn:fail:contract:continuation]. The @racket[v]s are delivered 81as arguments to the target prompt's handler procedure. 82 83The protocol for @racket[v]s supplied to an abort is specific to the 84@racket[prompt-tag]. When @racket[abort-current-continuation] is used with 85@racket[(default-continuation-prompt-tag)], generally, a single thunk 86should be supplied that is suitable for use with the default prompt 87handler. Similarly, when @racket[call-with-continuation-prompt] is 88used with @racket[(default-continuation-prompt-tag)], the associated 89handler should generally accept a single thunk argument. 90 91Each @tech{thread}'s continuation starts with a prompt for 92@racket[(default-continuation-prompt-tag)] that uses the default 93handler, which accepts a single thunk to apply (with the prompt 94intact).} 95 96@defproc*[([(make-continuation-prompt-tag) continuation-prompt-tag?] 97 [(make-continuation-prompt-tag [name symbol?]) continuation-prompt-tag?])]{ 98 99Creates a prompt tag that is not @racket[equal?] to the result of any 100other value (including prior or future results from 101@racket[make-continuation-prompt-tag]). The optional @racket[name] 102argument, if supplied, specifies the name of the prompt tag 103for printing or @racket[object-name]. 104 105@history[#:changed "7.9.0.13" @elem{The @racket[name] argument 106 gives the name of the prompt tag.}] 107} 108 109@defproc[(default-continuation-prompt-tag) continuation-prompt-tag?]{ 110 111Returns a constant prompt tag for which a prompt is installed at the 112start of every thread's continuation; the handler for each thread's 113initial prompt accepts any number of values and returns. The result of 114@racket[default-continuation-prompt-tag] is the default tag for 115any procedure that accepts a prompt tag.} 116 117@defproc[(call-with-current-continuation 118 [proc (continuation? . -> . any)] 119 [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]) 120 any]{ 121 122Captures the current continuation up to the nearest prompt tagged by 123@racket[prompt-tag]; if no such prompt exists, the 124@exnraise[exn:fail:contract:continuation]. The truncated continuation 125includes only continuation marks and @racket[dynamic-wind] frames 126installed since the prompt. 127 128The captured continuation is delivered to @racket[proc], which is 129called in tail position with respect to the 130@racket[call-with-current-continuation] call. 131 132If the continuation argument to @racket[proc] is ever applied, then it 133removes the portion of the current continuation up to the nearest 134prompt tagged by @racket[prompt-tag] (not including the prompt; if no 135such prompt exists, the @exnraise[exn:fail:contract:continuation]), or 136up to the nearest continuation frame (if any) shared by the current 137and captured continuations---whichever is first. While removing 138continuation frames, @racket[dynamic-wind] @racket[_post-thunk]s are 139executed. Finally, the (unshared portion of the) captured continuation 140is appended to the remaining continuation, applying 141@racket[dynamic-wind] @racket[_pre-thunk]s. 142 143The arguments supplied to an applied procedure become the result 144values for the restored continuation. In particular, if multiple 145arguments are supplied, then the continuation receives multiple 146results. 147 148If, at application time, a @tech{continuation barrier} would be 149introduced by replacing the current continuation with the applied one, 150then the @exnraise[exn:fail:contract:continuation]. 151 152A continuation can be invoked from the thread (see 153@secref["threads"]) other than the one where it was captured.} 154 155@defproc[(call/cc 156 [proc (continuation? . -> . any)] 157 [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]) 158 any]{ 159 160The @racket[call/cc] binding is an alias for @racket[call-with-current-continuation]. 161} 162 163@defproc[(call-with-composable-continuation 164 [proc (continuation? . -> . any)] 165 [prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]) 166 any]{ 167 168Similar to @racket[call-with-current-continuation], but applying 169the resulting continuation procedure does not remove any portion of 170the current continuation. Instead, application always extends the 171current continuation with the captured continuation (without 172installing any prompts other than those captured in the 173continuation). 174 175When @racket[call-with-composable-continuation] is called, if a 176continuation barrier appears in the continuation before the closest 177prompt tagged by @racket[prompt-tag], the 178@exnraise[exn:fail:contract:continuation] (because attempting to apply 179the continuation would always fail).} 180 181@defproc[(call-with-escape-continuation 182 [proc (continuation? . -> . any)]) 183 any]{ 184 185Like @racket[call-with-current-continuation], but @racket[proc] is not 186called in tail position, and the continuation procedure supplied to 187@racket[proc] can only be called during the dynamic extent of the 188@racket[call-with-escape-continuation] call. 189 190A continuation obtained from @racket[call-with-escape-continuation] is 191actually a kind of prompt. Escape continuations are provided mainly 192for backwards compatibility, since they pre-date general prompts in 193Racket. In the @tech{BC} implementation of Racket, 194@racket[call-with-escape-continuation] is implemented more efficiently 195than @racket[call-with-current-continuation], so 196@racket[call-with-escape-continuation] can sometimes replace 197@racket[call-with-current-continuation] to improve performance in 198those older Racket variants.} 199 200@defproc[(call/ec 201 [proc (continuation? . -> . any)]) 202 any]{ 203 204The @racket[call/ec] binding is an alias for @racket[call-with-escape-continuation]. 205} 206 207@defproc[(call-in-continuation [k continuation?] 208 [proc (-> any)]) 209 any]{ 210 211Similar to applying the continuation @racket[k], but instead of 212delivering values to the continuation, @racket[proc] is called with 213@racket[k] as the continuation of the call (so the result of 214@racket[proc] is returned to the continuation). If @racket[k] 215is a composable continuation, the continuation of the call to 216@racket[proc] is the current continuation extended with @racket[k]. 217 218@mz-examples[ 219(+ 1 220 (call/cc (lambda (k) 221 (call-in-continuation k (lambda () 4))))) 222(+ 1 223 (call/cc (lambda (k) 224 (let ([n 0]) 225 (dynamic-wind 226 void 227 (lambda () 228 (code:comment @#,elem{@racket[n] accessed after post thunk}) 229 (call-in-continuation k (lambda () n))) 230 (lambda () 231 (set! n 4))))))) 232(+ 1 233 (with-continuation-mark 234 'n 4 235 (call/cc (lambda (k) 236 (with-continuation-mark 237 'n 0 238 (call-in-continuation 239 k 240 (lambda () 241 (code:comment @#,elem{@racket['n] mark accessed in continuation}) 242 (continuation-mark-set-first #f 'n)))))))) 243] 244 245@history[#:added "7.6.0.17"]} 246 247@defform[(let/cc k body ...+)]{ 248Equivalent to @racket[(call/cc (lambda (k) body ...))]. 249} 250 251@defform[(let/ec k body ...+)]{ 252Equivalent to @racket[(call/ec (lambda (k) body ...))]. 253} 254 255@defproc[(call-with-continuation-barrier [thunk (-> any)]) any]{ 256 257Applies @racket[thunk] with a @tech{continuation barrier} between the 258application and the current continuation. The results of 259@racket[thunk] are the results of the 260@racket[call-with-continuation-barrier] call.} 261 262 263@defproc[(continuation-prompt-available? 264 [prompt-tag continuation-prompt-tag?] 265 [cont continuation? (call/cc values)]) 266 any]{ 267 268Returns @racket[#t] if @racket[cont], which must be a continuation, 269includes a prompt tagged by @racket[prompt-tag], @racket[#f] 270otherwise. 271} 272 273@defproc[(continuation? [v any/c]) boolean?]{ Return @racket[#t] if 274@racket[v] is a continuation as produced by 275@racket[call-with-current-continuation], 276@racket[call-with-composable-continuation], or 277@racket[call-with-escape-continuation], @racket[#f] otherwise.} 278 279@defproc[(continuation-prompt-tag? [v any/c]) boolean?]{ 280Returns @racket[#t] if @racket[v] is a continuation prompt tag as produced by 281@racket[default-continuation-prompt-tag] or @racket[make-continuation-prompt-tag].} 282 283@defproc[(dynamic-wind [pre-thunk (-> any)] 284 [value-thunk (-> any)] 285 [post-thunk (-> any)]) 286 any]{ 287 288Applies its three thunk arguments in order. The value of a 289@racket[dynamic-wind] expression is the value returned by 290@racket[value-thunk]. The @racket[pre-thunk] procedure is invoked 291before calling @racket[value-thunk] and @racket[post-thunk] is invoked 292after @racket[value-thunk] returns. The special properties of 293@racket[dynamic-wind] are manifest when control jumps into or out of 294the @racket[value-thunk] application (either due to a prompt abort or 295a continuation invocation): every time control jumps into the 296@racket[value-thunk] application, @racket[pre-thunk] is invoked, and 297every time control jumps out of @racket[value-thunk], 298@racket[post-thunk] is invoked. (No special handling is performed for 299jumps into or out of the @racket[pre-thunk] and @racket[post-thunk] 300applications.) 301 302When @racket[dynamic-wind] calls @racket[pre-thunk] for normal 303evaluation of @racket[value-thunk], the continuation of the 304@racket[pre-thunk] application calls @racket[value-thunk] (with 305@racket[dynamic-wind]'s special jump handling) and then 306@racket[post-thunk]. Similarly, the continuation of the 307@racket[post-thunk] application returns the value of the preceding 308@racket[value-thunk] application to the continuation of the entire 309@racket[dynamic-wind] application. 310 311When @racket[pre-thunk] is called due to a continuation jump, the 312continuation of @racket[pre-thunk] 313 314@itemize[ 315 316 @item{jumps to a more deeply nested @racket[pre-thunk], if any, or jumps 317 to the destination continuation; then} 318 319 @item{continues with the context of the @racket[pre-thunk]'s 320 @racket[dynamic-wind] call.} 321 322] 323 324Normally, the second part of this continuation is never reached, due 325to a jump in the first part. However, the second part is relevant 326because it enables jumps to escape continuations that are contained in 327the context of the @racket[dynamic-wind] call. Furthermore, it means 328that the continuation marks (see @secref["contmarks"]) and 329parameterization (see @secref["parameters"]) for @racket[pre-thunk] 330correspond to those of the @racket[dynamic-wind] call that installed 331@racket[pre-thunk]. The @racket[pre-thunk] call, however, is 332@racket[parameterize-break]ed to disable breaks (see also 333@secref["breakhandler"]). 334 335Similarly, when @racket[post-thunk] is called due to a continuation 336jump, the continuation of @racket[post-thunk] jumps to a less deeply 337nested @racket[post-thunk], if any, or jumps to a @racket[pre-thunk] 338protecting the destination, if any, or jumps to the destination 339continuation, then continues from the @racket[post-thunk]'s 340@racket[dynamic-wind] application. As for @racket[pre-thunk], the 341parameterization of the original @racket[dynamic-wind] call is 342restored for the call, and the call is @racket[parameterize-break]ed 343to disable breaks. 344 345In both cases, the target for a jump is recomputed after each 346@racket[pre-thunk] or @racket[post-thunk] completes. When a 347prompt-delimited continuation (see @secref["prompt-model"]) is 348captured in a @racket[post-thunk], it might be delimited and 349instantiated in such a way that the target of a jump turns out to be 350different when the continuation is applied than when the continuation 351was captured. There may even be no appropriate target, if a relevant 352prompt or escape continuation is not in the continuation after the 353restore; in that case, the first step in a @racket[pre-thunk] or 354@racket[post-thunk]'s continuation can raise an exception. 355 356@examples[ 357(let ([v (let/ec out 358 (dynamic-wind 359 (lambda () (display "in ")) 360 (lambda () 361 (display "pre ") 362 (display (call/cc out)) 363 #f) 364 (lambda () (display "out "))))]) 365 (when v (v "post "))) 366 367(let/ec k0 368 (let/ec k1 369 (dynamic-wind 370 void 371 (lambda () (k0 'cancel)) 372 (lambda () (k1 'cancel-canceled))))) 373 374(let* ([x (make-parameter 0)] 375 [l null] 376 [add (lambda (a b) 377 (set! l (append l (list (cons a b)))))]) 378 (let ([k (parameterize ([x 5]) 379 (dynamic-wind 380 (lambda () (add 1 (x))) 381 (lambda () (parameterize ([x 6]) 382 (let ([k+e (let/cc k (cons k void))]) 383 (add 2 (x)) 384 ((cdr k+e)) 385 (car k+e)))) 386 (lambda () (add 3 (x)))))]) 387 (parameterize ([x 7]) 388 (let/cc esc 389 (k (cons void esc))))) 390 l) 391]} 392 393@; ---------------------------------------------------------------------- 394 395@include-section["control-lib.scrbl"] 396