This is related to What is call/cc?, but I didn't want to hijack this question for my own purposes, and some of its arguments like the analogy to setjmp/longjmp evade me.
I think I have a sufficient idea about what a continuation is, I think of it as a snapshot of the current call stack. I don't want to go into the discussion why this might be interesting or what you can do with continuations. My question is more specifically, why do I have to provide a function argument to call/cc? Why doesn't call/cc just return the current continuation, so I could do whatever I please with it (store it, call it, you name it)? In a link from this other question (http://community.schemewiki.org/?call-with-current-continuation-for-C-programmers), it talks about "Essentially it's just a clean way to get the continuation to you and keep out of the way of subsequent jumps back to the saved point.", but I'm not getting it. It seems unnecessarily complicated.
If you use a construct like Jay shows, then you can grab the continuation, but in a way, the value that is grabbed is already spoiled because you're already inside that continuation. In contrast, call/cc
can be used to grab the continuation that is still pending outside of the current expression. For example, one of the simplest uses of continuations is to implement a kind of an abort
:
(call/cc (lambda (abort)
(+ 1 2 (abort 9))))
You cannot do that with the operation you describe. If you try it:
(define (get-cc) (call/cc values))
(let ([abort (get-cc)]) (+ 1 2 (abort 9)))
then you get an error about applying 9
as a procedure. This happens because abort
jumps back to the let
with the new value of 9
-- which means that you're now doing a second round of the same addition expression, except that now abort
is bound to 9
...
Two additional related notes:
call/cc
is a little complex in that it takes in a function -- a conceptually easier to use construct is let/cc
which you can find in some implementations like PLT Scheme. The above example becomes (let/cc abort (+ 1 2 (abort 9)))
.That would be less versatile. If you want that behavior, you can just do:
(call/cc (lambda (x) x))
You could take a look at the example usages of continuations in "Darrell Ferguson and Dwight Deugo. "Call with Current Continuation Patterns". 8th Conference on Pattern Languages of Programs. September 2001." (http://library.readscheme.org/page6.html) and try to rewrite them using a call/cc-return, defined as above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With