Next: Application Hooks, Previous: Primitive Procedures, Up: Procedures
Procedure must be a procedure of one argument. Packages up the current continuation (see below) as an escape procedure and passes it as an argument to procedure. The escape procedure is a Scheme procedure of one argument that, if it is later passed a value, will ignore whatever continuation is in effect at that later time and will give the value instead to the continuation that was in effect when the escape procedure was created. The escape procedure created by
call-with-current-continuation
has unlimited extent just like any other procedure in Scheme. It may be stored in variables or data structures and may be called as many times as desired.The following examples show only the most common uses of this procedure. If all real programs were as simple as these examples, there would be no need for a procedure with the power of
call-with-current-continuation
.(call-with-current-continuation (lambda (exit) (for-each (lambda (x) (if (negative? x) (exit x))) '(54 0 37 -3 245 19)) #t)) => -3 (define list-length (lambda (obj) (call-with-current-continuation (lambda (return) (letrec ((r (lambda (obj) (cond ((null? obj) 0) ((pair? obj) (+ (r (cdr obj)) 1)) (else (return #f)))))) (r obj)))))) (list-length '(1 2 3 4)) => 4 (list-length '(a b . c)) => #fA common use of
call-with-current-continuation
is for structured, non-local exits from loops or procedure bodies, but in factcall-with-current-continuation
is quite useful for implementing a wide variety of advanced control structures.Whenever a Scheme expression is evaluated a continuation exists that wants the result of the expression. The continuation represents an entire (default) future for the computation. If the expression is evaluated at top level, for example, the continuation will take the result, print it on the screen, prompt for the next input, evaluate it, and so on forever. Most of the time the continuation includes actions specified by user code, as in a continuation that will take the result, multiply it by the value stored in a local variable, add seven, and give the answer to the top-level continuation to be printed. Normally these ubiquitous continuations are hidden behind the scenes and programmers don't think much about them. On the rare occasions that you may need to deal explicitly with continuations,
call-with-current-continuation
lets you do so by creating a procedure that acts just like the current continuation.
Thunk must be a procedure of no arguments. Conceptually,
within-continuation
invokes continuation on the result of invoking thunk, but thunk is executed in the dynamic context of continuation. In other words, the “current” continuation is abandoned before thunk is invoked.
Calls thunk without arguments, returning the result(s) of this call. Before and after are called, also without arguments, as required by the following rules (note that in the absence of calls to continuations captured using
call-with-current-continuation
the three arguments are called once each, in order). Before is called whenever execution enters the dynamic extent of the call to thunk and after is called whenever it exits that dynamic extent. The dynamic extent of a procedure call is the period between when the call is initiated and when it returns. In Scheme, because ofcall-with-current-continuation
, the dynamic extent of a call may not be a single, connected time period. It is defined as follows:
- The dynamic extent is entered when execution of the body of the called procedure begins.
- The dynamic extent is also entered when execution is not within the dynamic extent and a continuation is invoked that was captured (using
call-with-current-continuation
) during the dynamic extent.- It is exited when the called procedure returns.
- It is also exited when execution is within the dynamic extent and a continuation is invoked that was captured while not within the dynamic extent.
If a second call to
dynamic-wind
occurs within the dynamic extent of the call to thunk and then a continuation is invoked in such a way that the afters from these two invocations ofdynamic-wind
are both to be called, then the after associated with the second (inner) call todynamic-wind
is called first.If a second call to
dynamic-wind
occurs within the dynamic extent of the call to thunk and then a continuation is invoked in such a way that the befores from these two invocations ofdynamic-wind
are both to be called, then the before associated with the first (outer) call todynamic-wind
is called first.If invoking a continuation requires calling the before from one call to
dynamic-wind
and the after from another, then the after is called first.The effect of using a captured continuation to enter or exit the dynamic extent of a call to before or after is undefined.
(let ((path '()) (c #f)) (let ((add (lambda (s) (set! path (cons s path))))) (dynamic-wind (lambda () (add 'connect)) (lambda () (add (call-with-current-continuation (lambda (c0) (set! c c0) 'talk1)))) (lambda () (add 'disconnect))) (if (< (length path) 4) (c 'talk2) (reverse path)))) => (connect talk1 disconnect connect talk2 disconnect)
The following two procedures support multiple values.
Thunk must be a procedure of no arguments, and procedure must be a procedure. Thunk is invoked with a continuation that expects to receive multiple values; specifically, the continuation expects to receive the same number of values that procedure accepts as arguments. Thunk must return multiple values using the
values
procedure. Then procedure is called with the multiple values as its arguments. The result yielded by procedure is returned as the result ofcall-with-values
.