Chris Bitmead <Chris.Bitmead@Alcatel.com.au> wrote:
+---------------
| So is my understanding right? Is the escape procedure dead once
| call/cc returns?
+---------------
*NO!* ...and that's one of the things that makes implementation
of full Scheme continuations "interesting" in a C stack environment.
Consider the following (and ignore the fact that we could do it more
simply by making "foo" be a closure over the let):
> (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
> (foo)
4
>
See??!? No way can you do that with a simple setjmp/longjmp!
For this reason, most (all?) Schemes that use the C stack for
procedure calls implement call/cc by copying the *entire* stack
(and the current active registers, don't forget them!) into
the heap as part of the continuation object, and then if this
continuation is ever invoked, they overwrite the then-active
stack (and registers, including the stack pointer) with the
saved heap information, and "return". (...*without* altering
the saved heap object!)
-Rob
p.s. Because this can be quite expensive when the stack is deep,
many C-based Schemes also provide a more limited non-local break,
sometimes called "call/ec" (call with escaping continuation),
which mirrors the normal "use-once" setjmp/longjmp.
p.p.s. Note that if full call/cc is used when the stack is fairly
shallow, e.g., for implementing (nearly) top-level coroutines or
"processes" or the like, it's actually not *too* expensive...
-----
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