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:

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

Back