Skip to content

ControlFeaturesInternals

leftmike edited this page May 14, 2016 · 2 revisions

Continuation Marks

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.

Continuations

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.

Clone this wiki locally