Reputation: 29
In the expression (call/cc (lambda (k) (k 12)))
, there are three continuations: (k 12)
, (lambda (k) (k 12))
, and (call/cc (lambda (k) (k 12)))
. Which one is the "current continuation"?
And continuations in some books are viewed as a procedure which is waiting for a value and it will return immediately when it's applied to a value. Is that right?
Can anyone explain what current continuations are in detail?
Upvotes: 1
Views: 105
Reputation: 1193
Things like (k 12)
are not continuations. There is a continuation associated with each subexpression in some larger program. So for example, the continuation of x
in (* 3 (+ x 42))
is (lambda (_) (* 3 (+ _ 42)))
.
In your example, the "current continuation" of (call/cc (lambda (k) (k 12)))
would be whatever is surrounding that expression. If you just typed it into a scheme prompt, there is nothing surrounding it, so the "current continuation" is simply (lambda (_) _)
. If you typed something like (* 3 (+ (call/cc (lambda (k) (k 12))) 42))
, then the continuation is (lambda (_) (* 3 (+ _ 42)))
.
Note that the lambdas I used to represent the "current continuation" are not the same as what call/cc
passes in (named k
in your example). k
has a special control effect of aborting the rest of the computation after evaluating the current continuation.
Upvotes: 2
Reputation: 222993
The continuation in this case is the "thing" that receives the return value of the call/cc
invocation. Thus:
(display (call/cc (lambda (k) (k 12)))
has the same result as
(display 12)
Continuations in Scheme "look and feel" like procedures, but they do not actually behave like procedures. One thing that can help you understand continuations better is CPS transformations.
In CPS transformation, instead of a function returning a value, instead it takes a continuation parameter, and invokes the continuation with the result. So, a CPS-transformed sqrt
function would be invoked with (sqrt 64 k)
and rather than returning 8, it just invokes (k 8)
in tail position.
Because continuations (in a CPS-transformed function) are tail-called, the function doesn't have to worry about the continuation returning, and in fact, in most cases, they are not expected to return.
With this in mind, here's a simple example of a function:
(define (hypot x y)
(sqrt (+ (* x x) (* y y))))
and its CPS-transformed version:
(define (hypot x y k)
(* x x (lambda (x2)
(* y y (lambda (y2)
(+ x2 y2 (lambda (sum)
(sqrt sum k))))))))
(assuming that *
, +
, and sqrt
have all been CPS-transformed also, to accept a continuation argument).
So now, the interesting part: a CPS-transformed call/cc
has the following definition:
(define (call/cc fn k)
(fn k k))
With CPS transformation, call/cc
is easy to understand and easy to implement. Without CPS transformation, call/cc
is likely to require a highly magical implementation (e.g., via stack copying, etc.).
Upvotes: 1