I read this after perusing the linked resources last time it surfaced, and although I'm no expert, I really like this solution. I'd love to hear from the Scheme implimentors and macro-writers who have actually used call/cc. The control offered over the scope of a continuation, reminding me (model-wise) of a patchset cherry-picked off the head of a git branch, appesrs to soundly address preformance concerns, while the ability to return a value to the continuation's call-site looks like a huge advantage.
"Finally, a primitive (call-in-continuation) is provided that allows calling a procedure in a given continuation instead of just delivering values to it."
can anyone add some language about what this is? I read this and the section on it, and remain deeply confused
First, just some context, to be sure I've got my facts straight:
'call/cc' allows you to capture the continuation which invokes it. That continuation is represented as a procedure passed into a unary function. That function usually uses 'set!' to export the continuation into a broader scope before returning an initial value to call/cc's caller. Later, invoking that continuation with a value tosses your current continuation and returns you to the call-site of call/cc, where the call/cc form now returns to it's caller again but with the provided value.
In contrast, 'call-in-continuation' takes a procedure and some arguments. It tosses the current continuation, returning to the call-site of call/cc, but then instead of returning a supplied value directly to call/cc's caller, it returns the result of evaluating the given procedure (applying it to any other supplied arguments) here at the call/cc call-site.
Supplied arguments are evaluated before returning to the continuation, just like when invoking the continuation itself with some values.
Mirroring the example from Guile's docs[1]:
(define kont #f)
(let ((x 1))
(format #t "the return is ~a\n"
(call/cc (lambda (k)
(set! kont k)
(1+ x)))))
⇒ the return is 2
(kont 3)
⇒ the return is 3
(kont (+ x 3))
⇒ Unbound variable: x
(kont (lambda () (+ x 3))
⇒ the return is #<procedure 1d823a8 at <unknown port>:5:6 ()>
(call-in-continuation kont (lambda () (+ x 3)))
⇒ the return is 4
(call-in-continuation kont (lambda (y) (+ x y)) 4)
⇒ the return is 5
Oh, and a note on why you'd want this: while you may be able to construct a superficially similar example by expecting call/cc to return a thunk and evaluating it at the call-site, you can't always control the call-site and might be using one continuation in multiple contexts.
The try/catch implementation on page two of A Better API for First Class Continuations show-cases a specific use-case (albeit in the form of continuation-graft), though I'm still staring at it and trying to figure out if a few more parens and thunks wouldn't do the trick (more verbosely) in that context.