continuation(programming)
Informally speaking, the word "continuation" in programming refers to the concept of "things that comes after". When we talk about continuations in Racket there are two kinds of them: the normal one (we shall call it "normal continuation" in this tutorial), which is "things that comes after till the calls end"; and the one called "delimited continuation", which is "things that comes after up till a certain point". What do I mean by "till the calls end"? Sometimes you'll have functions that call other functions, and such calls can nest a positive amount of levels; "till the calls end" means until the very last call (or should I say the first call invoked?) ends.
(Of course the "up till a certain point" part includes the point where the first call returns, which makes it essentially the same as the first kind. In this sense you can say delimited continuation is a generalization of the normal kind of continuation. )
In Scheme and Racket, one can captures this "everything that comes after" and turns it into a value that you can use (literatures call this "reification"); you use these values like normal functions. For example:
(define the-rest (void)) (define (my-func) ;; call/cc, full name call-with-current-continuation, is an operator ;; to capture the normal continuation at the point of usage. (call/cc (lambda (k) (set! the-rest k) 0))) (+ 1 (+ 1 (+ 1 (my-func))))
The happening order of things goes as follows:
- The
(+ 1 (+ 1 (+ 1
part happens; by the time it reaches the call tomy-func
, there are 3 calls of(+ 1
on the call stack. my-func
gets invoked. The continuation - which is the three(+ 1
calls in this case - is reified and passed to the anonymous function as the argumentk
.- The anonymous function assigns
k
to the namethe-rest
, and then returns0
; thus the whole call tomy-func
results in0
. - The expression becomes
(+ 1 (+ 1 (+ 1 0)))
, which evaluates to3
.
At this point, since the three calls to (+ 1
is actually saved to the variable the-rest
, you can use it as if it were just an ordinary function in the first place:
(the-rest 5) ;; returns 8 (the-rest 7) ;; returns 10 (the-rest 9) ;; returns 12
We must look at another example about continuations, because the way continuation works is different from normal functions. If we assume that the value behind the name k
in the example above behaves exactly like the function (lambda (x) (+ 1 (+ 1 (+ 1 x))))
, then you'll be wrong. Assume that the anonymous function is like this instead of the one above:
(define (my-func) (call/cc (lambda (k) (displayln (k 3)) (displayln ((lambda (v) (+ 1 (+ 1 (+ 1 v)))) 3)) 0))) (+ 1 (+ 1 (+ 1 (my-func))))
If k
were indeed a normal function, then the two calls to displayln
should be equivalent, thus it should display 6
twice; but the result is that it won't display 6
even once; because when the continuation is invoked, the execution immediately skipped to the point when call/cc
is invoked to capture the continuation.
2024.7.28