Subject: Re: Trouble with CALL/CC
From: (Rob Warnock)
Date: 1997/01/24
Newsgroups: comp.lang.scheme
Message-ID: <5c9ef3$>

Chris Bitmead <> 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)
   	> (* 17 (+ 12 (bar) 29))

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).


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
Silicon Graphics, Inc.
2011 N. Shoreline Blvd.		Phone: 415-933-1673  FAX: 415-933-0979
Mountain View, CA  94043	PP-ASEL-IA