On Sun, Mar 20, 2011 at 4:58 PM, Gregory Woodhouse <gregwoodho...@me.com> wrote: > If I write a trivial loop using call/cc > > (call/cc > (lambda (k) > (define (loop) > (let ([x (read)]) > (if (eq? x '()) > (k x) > (loop)))) > (loop))) > > It does exactly what I expect. If I type anything but () it reads again, but > if I type () it prints out '() and quits > > Welcome to DrRacket, version 5.1 [3m]. > Language: racket; memory limit: 256 MB. > hello <-- user input > '() <-- user input > () <-- user input > '() <-- output >> > > but if I change call/cc to call-with-composable-continuatiom I see '() > printed twice > > Welcome to DrRacket, version 5.1 [3m]. > Language: racket; memory limit: 256 MB. > hello <-- user input > () <-- user input > '() <-- output > '() <-- output >> > > Why is this?
Expressions that appear at the top-level of a module have some implicit context wrapped around them. This context becomes part of k in your examples. When you write the expression e, what's actually run is something more like this: (call-with-continuation-prompt (λ () ((λ (x) (begin (displayln x) x)) e))) Your uses of `call/cc' and `call-with-composable-continuation' both capture everything up to the continuation prompt, making k represent the context ((λ (x) (begin (displayln x) x)) []) where [] is its "hole" (i.e., the position that receives returned values). The difference in the two examples is what happens when you apply k. In the `call/cc' example, applying k throws out the current continuation ((λ (x) (begin (displayln x) x)) []) replaces it with k (which happens to be exactly the same), and places '() in the hole, causing it to be printed once. In the `call-with-composable-continuation' example, applying k extends the current continuation with k, producing this continuation: ((λ (x) (begin (displayln x) x)) ((λ (x) (begin (displayln x) x)) [])) When this extended context receives the value '(), it prints it twice. If you'd like to see this process in action, you could try experimenting with the Redex model of Racket's control operators. Be warned, though, that the notation is a little different than what Racket actually provides. To get a feel for how the model works, try this program: #lang racket (require redex redex/examples/delim-cont/reduce) (stepper :-> (term (<> ([loop (λ (i) (if (zero? i) 0 (begin (print i) (loop (+ i -1)))))]) [] (print (loop 5))))) It pops up a window showing the steps taken in the execution of a simple program. Programs in the model have the general shape (<> ([x v] ...) [] e) where [x v] is a top-level definition, [] is the numbers printed so far (initially none), and e is an expression. Here's a program you can run in the model that's similar to your `call/cc' program. (<> ([loop (λ (i k) (if (zero? i) (k 0) (begin (print i) (loop (+ i -1) k))))]) [] (% 0 ((λ (x) (begin (print x) x)) (call/cc (λ (k) (loop 5 k)) 0)) (λ (x) x))) The model's `%' form is roughly Racket's `call-with-continuation-prompt' procedure. For now, you can ignore its first and third sub-expressions. You can also ignore the second argument to `call/cc' and the `wcm' business that will appear when you step through the program's execution. To see the difference that `call-with-composable-continuation' makes, change `call/cc' to `call/comp' in the model program. _________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/users