💾 Archived View for idiomdrottning.org › call-with-current-continuation captured on 2023-11-04 at 12:13:20. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2021-12-03)

➡️ Next capture (2024-02-05)

-=-=-=-=-=-=-

a call-with-current-continuation is a simple thing

Normally 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!♥

What about 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)))

Why is it called 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.