To evaluate a sub-expression, MzScheme creates a continuation for the
sub-expression that extends the current continuation. For example, to
evaluate expr in the expression
(begin
expr
expr )
MzScheme extends the continuation of the begin expression
with one continuation frame to create the continuation for
expr . In contrast, expr is in tail position for the begin expression, so its continuation is the
same as the continuation of the begin expression.
A continuation mark is a keyed mark in a continuation frame. A program can install a mark in the first frame of its current continuation, and it can extract the marks from all of the frames in its current continuation. Continuation marks support debuggers and other program-tracing facilities, because continuation frames roughly correspond to stack frames in traditional languages. For example, a debugger can annotate a source program to store continuation marks that relate each expression to its source location; when an exception occurs, the marks are extracted from the current continuation to produce a ``stack trace'' for the exception.
The list of continuation marks for a key k and a continuation C that extends C is defined as follows:
The with-continuation-mark form installs a mark on the
first frame of the current continuation:
(with-continuation-mark key-expr mark-expr
body-expr)
The key-expr, mark-expr, and body-expr expressions
are evaluated in order. After key-expr is evaluated to obtain a
key and mark-expr is evaluated to obtain a mark, the key is
mapped to the mark in the current continuation's initial frame. If
the frame already has a mark for the key, it is replaced. Finally,
the body-expr is evaluated; the continuation for evaluating
body-expr is the continuation of the
with-continuation-mark expression (so the result of the
body-expr is the result of the with-continuation-mark
expression, and body-expr is in tail position for the
with-continuation-mark expression).
The current-continuation-marks procedure extracts the complete set of continuation marks from the current continuation:
The continuation-mark-set->list procedure extracts mark values for a particular key from a continuation mark set:
Examples:
(with-continuation-mark 'key 'mark
(extract-current-continuation-marks 'key)) ; => '(mark)
(with-continuation-mark 'key1 'mark1
(with-continuation-mark 'key2 'mark2
(list
(extract-current-continuation-marks 'key1)
(extract-current-continuation-marks 'key2)))) ; => '((mark1) (mark2))
(with-continuation-mark 'key 'mark1
(with-continuation-mark 'key 'mark2 ; replaces the previous mark
(extract-current-continuation-marks 'key)))) ; => '(mark2)
(with-continuation-mark 'key 'mark1
(list ; continuation extended to evaluate the argument
(with-continuation-mark 'key 'mark2
(extract-current-continuation-marks 'key)))) ; => '((mark1 mark2))
(let loop ([n 1000])
(if (zero? n)
(extract-current-continuation-marks 'key)
(with-continuation-mark 'key n
(loop (sub1 n))))) ; => '(1)
(define (extract-current-continuation-marks key)
(continuation-mark-set->list
(current-continuation-marks)
key))
In the final example, the continuation mark is set 1000 times, but extract-current-continuation-marks returns only one mark value. Because loop is called tail-recursively, the continuation of each call to loop is always the continuation of the entire expression. Therefore, the with-continuation-mark expression replaces the existing mark each time rather than adding a new one.
Whenever MzScheme creates an exception record, it fills the continuation-marks field with the value of (current-continuation-marks), thus providing a snapshot of the continuation marks at the time of the exception.
When a continuation procedure returned by call-with-current-continuation is invoked, it restores the captured continuation, and also restores the marks in the continuation's frames to the marks that were present when call-with-current-continuation was invoked.