Aly
Aly

Reputation: 935

How to interpret (call/cc call/cc)?

I'm familiar with using call/cc to interpret CPS programs in a direct style:

(define (f return)                                                                                                                               
  (return 2)                                                                                                                                     
  3)

(f (lambda (x) x))
=> 3

(call/cc f)
=> 2

I'm also familiar with how (call/cc call/cc) behaves, with ((call/cc call/cc) x) being equivalent to (x x):

((call/cc call/cc) display)
=> #<procedure #2 display>

The outer call/cc calls the argument call/cc with f that represents a continuation

(★ display)

But what continuation does the inner call/cc pass to f, considering that it wasn't called at a source location and was called as "part of a higher-order function"/"a value"?

If it's treated as being evaluated at the source location, intuition tells me it'll reduce similarly to:

((¹call/cc ²call/cc) display)
(²call/cc ¹(★ display))
(²((¹call/cc ★) display) display)
((¹call/cc display) display)
(display ¹(★ display))

which does not match the behavior (display display).

Upvotes: 1

Views: 366

Answers (1)

Gene
Gene

Reputation: 46990

Maybe you're being a bit misled by the Wikipedia page because it only explains continuations by examples, which are too limited to cover your question.

Every expression has a continuation representing everything that happens afterward. Conventionally we write

E[ expr ] c

to say "the meaning of expr with continuation c". Scheme implements a set of rules concerning such meanings. For example

E[ (+ A B) ] c = E[A] lambda (a) E[B] lambda (b) (c (+ a b))

The meaning of the Scheme addition of A and B is the meaning of A with a continuation that accepts that value and finds the meaning of B with a continuation that accepts that value, adds both values, and calls the continuation with the result as a parameter.

Okay. Now we're ready for the definition of call/cc:

E[ (call/cc F) ] c = E[ (F c) ] c

That is, the meaning of (call/cc f) with continuation c is the just the meaning of f applied to c with unchanged continuation. I think this answers your question: the continuation isn't altered by call/cc. It's just "exposed" as a parameter.

(This rule actually leaves stuff out for simplicity. Finding the meaning of F before it's called should be spelled out.)

So let's look at the case (call/cc call/cc):

E[ (call/cc call/cc) ] c = E[ (call/cc c) ] c = E[ (c c) ] c

That is, the meaning of (call/cc call/cc) is the continuation of this expression applied to itself.

For example, suppose we have ((call/cc call/cc) foo). The continuation here is (lambda (c) (c foo)) (as in the Wikipedia page). So the result will be:

((lambda (c) (c foo)) (lambda (c) (c foo))) => ((lambda (c) (c foo)) foo) => (foo foo)

So if foo is the identity, then so is the overall meaning of the expression.

I hope this is helpful.

Upvotes: 2

Related Questions