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