-
Notifications
You must be signed in to change notification settings - Fork 4
ControlFeaturesInternals
The implementation of continuation marks is based on John Clements' dissertation: Portable and high-level access to the stack with Continuation Marks.
The syntax with-continuation-mark
expands directly into a call to the procedure
%mark-continuation
.
(define-syntax with-continuation-mark
(syntax-rules ()
((_ key val expr) (%mark-continuation key val (lambda () expr)))))
procedure: (%mark-continuation who key val thunk)
%mark-continuation
looks at the front of the continuation to see what procedure it would
return to, if it were to return. If that procedure is %mark-continuation
and has the same
who then an existing mark with the same key can be updated or a new mark can be
added, and a tail call can be made to thunk. Otherwise, a new mark is placed on the
front of the continuation and a normal call is make to thunk. Note that updating an
existing mark only applies for marks at the front of the continuation.
(define dynamic-stack '())
(define (update-mark key val)
(let ((p (assq key (car dynamic-stack))))
(if p
(set-cdr! p val)
(set-car! dynamic-stack (cons (cons key val) (car dynamic-stack))))))
(define (%mark-continuation key val thunk)
(if (eq? (continuation-front-procedure) %mark-continuation)
(begin
(update-mark key val)
(thunk))
(begin
(set! dynamic-stack (cons (list (cons key val)) dynamic-stack))
(let-values ((v (thunk)))
(set! dynamic-stack (cdr dynamic-stack))
(apply values v))))))
The procedure continuation-front-procedure
returns the procedure on the front of the
continuation.
(define (a)
(define (b)
(continuation-front-procedure))
(let ((p (b)))
(eq? (b) a)))
=> #t
In the actual implementation, %mark-continuation
is a primitive. Frames on the dynamic stack
are created by calls to %mark-continuation
. Each frame is an object containing a list of
marks and a location in the continuation.
procedure: (%dynamic-stack)
procedure: (%dynamic-stack stack)
Get and set the dynamic stack.
procedure: (%dynamic-marks dynamic)
Get the list of marks contained in the dynamic frame.
(let ((ml (with-continuation-mark 'key 10
(%dynamic-marks (car (%dynamic-stack))))))
ml)
=> ((key . 10))
procedure: (%find-mark key default)
Find the first mark with key and return its values; otherwise return default.
The implementation of continuations is inspired by these two papers:
Matthew Flatt, Gang Yu, Robert Bruce Findler, and Matthias Felleisen. Adding Delimited and Composable Control to a Production Programming Environment http://www.cs.utah.edu/plt/publications/icfp07-fyff.pdf
Marc Feeley. A Better API for First-Class Continuations http://www.schemeworkshop.org/2001/feeley.pdf
Note that delimited and composable continuations are not yet supported.
procedure: (%capture-continuation proc)
Capture the current continuation as an object and pass it to proc.
procedure: (%call-continuation cont thunk)
Replace the current continuation with cont and call thunk. The continuation of thunk is cont.
procedure: (%abort-dynamic dynamic thunk)
Unwind the current continuation to location of dynamic and call thunk.