(continuation-capture f) --- calls f with the current continuation as argument. In contrast to call/cc, the continuation is not a procedure, but an opaque first-class object. (In Scheme 48, this is called primitive-cwcc.)
(continuation-graft k thunk) --- calls thunk in the continuation k. In contrast to call/cc, k doesn't receive a value computed in another continuation, but rather thunk's effect is performed in k. (Scheme 48: with-continuation.)
The implementation difference to call/cc is minimal, and expressing call/cc in terms of this API is simple:
(define (call/cc f) (continuation-capture (lambda (k) (f (lambda (val) (continuation-graft k (lambda () val)))))))
I can't exactly put my finger on it, but this API seems more powerful than call/cc. In the implementation of delimited dynamic binding in terms of continuation marks I'm working on, there is a need for fetching the marks of another continuation. With call/cc this is impossible, but with this API I can prepend a thunk to the continuation in question, then in this thunk fetch the continuation's marks, and then jump out of it again.
3 comments:
Well, Kernel has continuations as first class objects (and they aren't functions).
Continuation capture can be done with either call/cc or $let/cc. Then you have apply-continuation to call them (checking guards), guard-continuation to add guards, and extend continuation to add code (in the form of thunks).
Andres Navarro
Yes, Kernel's extend-continuation seems even more powerful than this API.
Totally agree. Representing continuations as functions doesn't make sense when they're first-class and not just a compiler technique. It's a lot easier to think of them in terms of stacks, too.
Post a Comment