Wednesday, August 1, 2012

An alternative API for continuations

Call/cc is the most well-known API for exposing first-class continuations to userland. But there is another API that's used in Scheme 48 and is also described in a paper by Feeley.

(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)
    (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.


Andres Navarro said...

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

Manuel Simoni said...

Yes, Kernel's extend-continuation seems even more powerful than this API.

Vladimir Sedach said...

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.