Continuations

A “continuation” is the rest of the computation that needs to be done.

`call-with-current-continuation` or `call/cc` gives you access to the current continuation. In fact, we can store this continuation and execute it multiple times.

Here’s how it works:

`call-with-current-continuation` stores the current continuation and calls a function you supply with a single argument. If return a value from your function, then that’s the return value of `call-with-current-continuation`. If you “call” the single argument with another argument, then execution of your function ends immediately and the return value of `call-with-current-continuation` is this other argument.

Confused? Let’s start with the first part of this description: `call-with-current-continuation` takes a single argument, a function that takes a single argument.

Take a look:

(define continuation #f)

(define (add-money balance amount)
  (call-with-current-continuation (lambda (cont)
				    (set! continuation cont)))
  (+ balance amount))

The anonymous function we pass to `call-with-current-continuation` receives a single argument, `cont`. Since we never call `cont`, the return value of our function is the return value of the call to `call-with-current-continuation`:

(add-money 10 2)
⇒ 12

At the point where `call-with-current-continuation` is called, the *continuation* is “Return the sum of `balance` and `amount`.”

Our anonymous function stores this continuation in the variable `continuation`.

And the value of `continuation`?

continuation
⇒ '#{Procedure 1319 (unnamed in continuation->procedure in wind)}

The result probably depends on your implementation.

Call it:

(continuation)
⇒ 12

We can call it as often as we want, jumping right back to where we were when `call-with-current-continuation` was called! In effect, we’re defining a jump target...

To be honest, we could have written the code above as follows:

(define (add-money balance amount)
  (set! continuation (lambda ()
		       (+ balance amount)))
  (continuation))

So what’s the difference between `call-with-current-continuation` and storing a lambda expression as we just did? The lambda expression is not really a jump target...

Here’s how we could exploit this jump target property: We can use `call-with-current-continuation` to define a *non-local exit*. The following example is from the Scheme Wiki call-with-current-continuation introduction:

call-with-current-continuation introduction

;;; Return the first element in LST for which WANTED? returns a true
;;; value.
(define (search wanted? lst)
  (call/cc
    (lambda (return)
      (for-each (lambda (element)
                  (if (wanted? element)
                      (return element)))
                lst)
      #f)))

Call it:

(search (lambda (el)
	  (integer? (/ el 3)))
	'(1 2 3 4 5))
⇒ 3

Why does it work? Apparently, the call to *return* exits the loop!

At the point where `call-with-current-continuation` is called, the *continuation* is “Return whatever the `call-with-current-continuation` returns.”

But what does it return? `call-with-current-continuation` takes a single argument, a procedure that takes the continuation as an argument. If you call this procedure with an argument, that’s the value returned by `call-with-current-continuation`.

In the above example, the continuation is called “return” and passed to an anonymous function that does a loop. Inside the loop, we call *return* with the correct element. Thus, search will return the element – jumping right back to where we were when `call-with-current-continuation` was called!

​#scheme