[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
6.13.5.1 Prompt Primitives
Guile’s primitive delimited control operators are
call-with-prompt
and abort-to-prompt
.
- Scheme Procedure: call-with-prompt tag thunk handler
Set up a prompt, and call thunk within that prompt.
During the dynamic extent of the call to thunk, a prompt named tag will be present in the dynamic context, such that if a user calls
abort-to-prompt
(see below) with that tag, control rewinds back to the prompt, and the handler is run.handler must be a procedure. The first argument to handler will be the state of the computation begun when thunk was called, and ending with the call to
abort-to-prompt
. The remaining arguments to handler are those passed toabort-to-prompt
.
- Scheme Procedure: make-prompt-tag [stem]
Make a new prompt tag. Currently prompt tags are generated symbols. This may change in some future Guile version.
- Scheme Procedure: default-prompt-tag
Return the default prompt tag. Having a distinguished default prompt tag allows some useful prompt and abort idioms, discussed in the next section.
- Scheme Procedure: abort-to-prompt tag val1 val2 …
Unwind the dynamic and control context to the nearest prompt named tag, also passing the given values.
C programmers may recognize call-with-prompt
and abort-to-prompt
as a fancy kind of setjmp
and longjmp
, respectively. Prompts are
indeed quite useful as non-local escape mechanisms. Guile’s catch
and
throw
are implemented in terms of prompts. Prompts are more convenient
than longjmp
, in that one has the opportunity to pass multiple values to
the jump target.
Also unlike longjmp
, the prompt handler is given the full state of the
process that was aborted, as the first argument to the prompt’s handler. That
state is the continuation of the computation wrapped by the prompt. It is
a delimited continuation, because it is not the whole continuation of the
program; rather, just the computation initiated by the call to
call-with-prompt
.
The continuation is a procedure, and may be reinstated simply by invoking it, with any number of values. Here’s where things get interesting, and complicated as well. Besides being described as delimited, continuations reified by prompts are also composable, because invoking a prompt-saved continuation composes that continuation with the current one.
Imagine you have saved a continuation via call-with-prompt:
(define cont (call-with-prompt ;; tag 'foo ;; thunk (lambda () (+ 34 (abort-to-prompt 'foo))) ;; handler (lambda (k) k)))
The resulting continuation is the addition of 34. It’s as if you had written:
(define cont (lambda (x) (+ 34 x)))
So, if we call cont
with one numeric value, we get that number,
incremented by 34:
(cont 8) ⇒ 42 (* 2 (cont 8)) ⇒ 84
The last example illustrates what we mean when we say, "composes with the
current continuation". We mean that there is a current continuation – some
remaining things to compute, like (lambda (x) (* x 2))
– and that
calling the saved continuation doesn’t wipe out the current continuation, it
composes the saved continuation with the current one.
We’re belaboring the point here because traditional Scheme continuations, as discussed in the next section, aren’t composable, and are actually less expressive than continuations captured by prompts. But there’s a place for them both.
Before moving on, we should mention that if the handler of a prompt is a
lambda
expression, and the first argument isn’t referenced, an abort to
that prompt will not cause a continuation to be reified. This can be an
important efficiency consideration to keep in mind.
One example where this optimization matters is escape continuations. Escape continuations are delimited continuations whose only use is to make a non-local exit—i.e., to escape from the current continuation. Such continuations are invoked only once, and for this reason they are sometimes called one-shot continuations. A common use of escape continuations is when throwing an exception (see section Exceptions).
The constructs below are syntactic sugar atop prompts to simplify the use of escape continuations.
- Scheme Procedure: call-with-escape-continuation proc
- Scheme Procedure: call/ec proc
Call proc with an escape continuation.
In the example below, the return continuation is used to escape the continuation of the call to
fold
.(use-modules (ice-9 control) (srfi srfi-1)) (define (prefix x lst) ;; Return all the elements before the first occurrence ;; of X in LST. (call/ec (lambda (return) (fold (lambda (element prefix) (if (equal? element x) (return (reverse prefix)) ; escape `fold' (cons element prefix))) '() lst)))) (prefix 'a '(0 1 2 a 3 4 5)) ⇒ (0 1 2)
- Scheme Syntax: let-escape-continuation k body …
- Scheme Syntax: let/ec k body …
Bind k within body to an escape continuation.
This is equivalent to
(call/ec (lambda (k) body …))
.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on April 20, 2013 using texi2html 5.0.