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