Chris Bitmead <Chris.Bitmead@Alcatel.com.au> wrote:
+---------------
| > > (define foo #f)
| > > (let ((counter 0))
| > (call/cc (lambda (k) (set! foo k)))
| > (set! counter (1+ counter))
| > counter)
| > 1
| > > (foo)
| > 2
| > > (* 17 (+ 12 (foo) 29))
| > 3
|
| Why does this evaluate to 3? I can see how every time you call foo,
| you jump back to where you were, and increment counter, and return
| counter. But how come when you return from foo, the rest of the (* 17
| (+12 etc doesn't get called?
+---------------
Because you never actually *return* from "foo" (it's a "tail call").
Instead, you return (again) from the "let" expression to the top-level
read-eval-print loop, which prints the "3" that the "let" expression
returned to it, then another prompt. [Mindbending at first, I know.]
The "current continuation" of a call/cc (what is passed to its arg proc)
is the entire sequence of instructions from the return of the call/cc
all the way out to the top-level REPL.
Perhaps my example was too simple. Augmenting it as follows may help:
> (define bar (lambda () (foo)))
> (bar)
4
> (* 17 (+ 12 (bar) 29))
5
At the point that the expression "(bar)" is about to be evaluated,
the continuation of the "*" expression is the top-level print routine,
the continuation of the "+" expression is the evaluation of the "*"
expression, and the continuation of the "(bar)" is the evaluation of
the "+" expression (that leads to the "*", that leads to the printing).
But when "bar" calls "foo", bar's continuation is *replaced* by the
continuation of the call/cc in the original "let" (which had been
saved in "foo"), and so instead of "bar" returning to finish the
evaluation of the "+" expression, the call/cc "returns again", which
executes the "set!" again (incrementing "counter" again), then returns
[the new value of] "counter" again to the top-level printer.
Neither the "+" nor the "*" functions will ever be called (although
depending on the order of argumant evaluation in your particular
implementation -- deliberately unspecified in Scheme -- each of "*",
"17", "+", "12", and "29" may or may not have been evaluated yet).
-Rob
p.s. By the way, it is precisely this that allows call/cc to emulate
"catch/throw" or "setjmp/longjmp" for abnormal or error exits. But
call/cc can also be used to do some things those other constructs
*can't* do (like the above)...
-----
Rob Warnock, 7L-551 rpw3@sgi.com
Silicon Graphics, Inc. http://reality.sgi.com/rpw3/
2011 N. Shoreline Blvd. Phone: 415-933-1673 FAX: 415-933-0979
Mountain View, CA 94043 PP-ASEL-IA