call-with-current-continuation
is a simple thingNormally in Scheme expressions return at the end of their forms, with the last value.
(begin 1 2 3 4)
Will return with 4.
What if we wanna return early?
What if there was a return
or break
or similar procedure (or we could
just give any name, like xyxxy
), and it’d return with that value?
(begin 1 2 (xyzzy 3) 4)
That’s fine, but where will it go?
At the place where you want to go, put a
(call-with-current-continuation (lambda (return-or-whatever) … ))
Like this:
(+ 3 4 (call-with-current-continuation
(lambda (xyzzy)
(begin 100 200 (xyzzy 300) 400))))
The call-with-current-continuation
form will return with a 300
making the expression as a whole 307.
It’s simple.
Like many simple things you can do a lot of fun things with it.
“Isn’t it kinda boring only being able to jump from inside out?”
Hohoho!
The return or xyzzy or whatever thing is a procedure, darling! In Scheme, procedures are values like any other value.
(define foxtrot #f)
(+ 3 4
(call-with-current-continuation
(lambda (xyzzy)
(set! foxtrot xyzzy)
(begin 100 200 (xyzzy 300) 400))))
(+ (foxtrot 1000) (foxtrot 2000))
That last form will evaluate to 1007, because it skips out with the first foxtrot
.
(begin "no matter when"
"no matter where"
(foxtrot 12)
"is a time machine")
That will evaluate to 19. Good luck, have lots of fun with continuations.♥︎ I can’t wait to see what you come up with.
People have used it to implement coroutines, generators, and
backtracking disambiguators and other complicated things.
call-with-current-continuation
is a simple tool but it’s a very
sharp knife. Don’t let anyone trick you into believing that the tool
itself is complicated. You can do it!♥︎
call/cc
?In some Schemes there is call/cc
which is just an alias for
call-with-current-continuation
. You save a couple of letters. If you
wanna use shortcuts, which I do, what I prefer is let/cc
from
Chicken’s miscmacros. That one saves you the entire lambda form.
(+ 3 4 (let/cc xyzzy (begin 100 200 (xyzzy 300) 400)))
call-with-current-continuation
?As simple as call-with-current-continuation
is, the reason for the
name is a li’l complicated though!
Here we go.
For a while the hype in Scheme was to use procedures rather macro bodies to do stuff. That was actually a good idea when you’re talking about the fundaments of the language, because they compose more easily.
These were often called “call-with-something-something”. So you might
have call-with-output-file
for example, that you gave a filename and
another procedure, and then that other procedure would be called with
a port to that file as its argument.
Like this:
(call-with-output-file "/tmp/example-cwof.txt"
(lambda (file) (display "hi" file)))
Now, that’s a little cumbersome and there are neater shortcuts when
you wanna write something to a file but that’s the sort of fundamental
building blocks Scheme was made out of. call-with-values
is another
oldie: it takes two procedures as argument and calls them, using the
values output by the first one as input to the other. These days I’d
use much less wordier wrappers like receive
or compose
when I do
multiple values stuff.
Anyway, so that explains the “call-with” part of the name. The lambda is what you call, the argument to lamba (the return or xyzzy or break or whatever you named it) is what you call it with.
From the examples it should be pretty clear what a continuation is.
The surrounding context, such as (+ 3 4 …)
where the computation
“continues”. Basically the area of the code that you wanna go to.