threads & dynamic environment & continuations
shivers@xxxxxx
(12 May 2000 01:20 UTC)
|
Re: threads & dynamic environment & continuations
Marc Feeley
(12 May 2000 01:55 UTC)
|
Re: threads & dynamic environment & continuations shivers@xxxxxx (12 May 2000 18:14 UTC)
|
Re: threads & dynamic environment & continuations
Marc Feeley
(12 May 2000 18:38 UTC)
|
Re: threads & dynamic environment & continuations
shivers@xxxxxx
(12 May 2000 18:44 UTC)
|
Re: threads & dynamic environment & continuations
Matthias Felleisen
(12 May 2000 02:46 UTC)
|
Re: threads & dynamic environment & continuations
shivers@xxxxxx
(12 May 2000 02:58 UTC)
|
> I think the current document should state these things explicitly. To sum up: > - dynamic env is part of the continuation, > - hence, throwing to a continuation changes the dynamic env. This was so "obvious" to me that I did not mention it. On the other hand, is it the role of SRFI 18 to specify this, or a dynamic environment SRFI? Well, your SRFI does not mention fluid-var sorts of notions at all, so if you are suggesting it's outside the scope of the SRFI, and up to a fluid-var SRFI to get it right, then I think you are right. However, SRFI-18 *does* explicitly mention the dynamic *exception* environment. So I think it *would* be a good thing to explicitly state this is part of the continuation. As for call/null-continuation, you can get the same result with call-with-current-continuation, if you also have dynamic variables. I.e. you capture the primordial continuation of the thread and bind that to a dynamic variable that you can then use to return to the primordial continuation. I don't think this gets you all the way home. For example, assume K is a continuation -- something we made with CALL/CC. This won't work: (k (thunk)) That sort-of punts the current continuation and "installs" K as the continuation for the THUNK call. But a simple implementation of Scheme wouldn't even realise that K was a continuation until THUNK had returned -- we wanted to punt the current stack eagerly, *before* we leapt off to THUNK. See the problem? However, it's worse than implementation/storage-leak issue -- we don't even get everything we wanted *semantically*. THUNK runs in the current dynamic environment (e.g., for exception handlers). We don't get to install K's dynamic env until THUNK returns and we do the call (throw) to THUNK. Oops. What I *wanted* was the ability to say "call THUNK with continuation K. That is, throw away the current continuation *now*, and *then* call THUNK -- run it with continuation K, *including* K's dynamic env." We still don't have that. So you gotta build it in. There are three paths I see: - A primitive like (call/continuation kont thunk) Calls THUNK with continuation KONT. The problem with this is that we are not "playing fair" with our continuations. Scheme continuations are *not* "true continuations." They are *procedures* that are somehow closed over a true continuation. CALL/CONTINUATION has to reach into KONT and pull out the true continuation in order to have KONT's dynamic env installed before running THUNK. So the procedures constructed by CALL/CC are somehow special -- i.e., KONT is not the same as (LAMBDA (X) (KONT X)) when KONT is a continuation made by CALL/CC. Oops. - A primitive like CALL/NULL-CONTINUATION We can use it like this (call/null-continuation (lambda () (kont (thunk)))) This solves our space-leak problem -- the CALL/NULL-CONTINUATION operator can drop the current stack & dynamic env *before* calling THUNK. But we haven't solved our semantics problem -- we still aren't running THUNK in KONT's dynamic environment. Oops. - Export the actual underlying non-procedure continuations: (call-with-current-kontinuation proc) (throw k val ...) ; THROW is n-ary -- 0 or more VAL's (call/kontinuation k thunk) ; Run THUNK with kontinuation K. ;; R5RS CALL/CC can be defined with the kontinuation mechanism: (define (call-with-current-continuation proc) (call-with-current-kontinuation (lambda (k) (proc (lambda vals (apply throw k vals)))))) This is an issue that bedevils thread/continuation implementations *all the time.* And it's sufficiently subtle that people never figure it out until their threaded programs start blowing out the heap mysteriously... and then there's no simple fix. Get it right now. Should SRFI 18 specify a mechanism for manipulating the dynamic environment? I'm fond of: (dynamic-define var-name expression) (dynamic-let ((var-name expression)) body) (dynamic-ref var-name) (dynamic-set! var-name expression) Note that in this scheme, dynamic variables and lexically scoped variables are completely independent. Uhh... I can see plusses & minusses. I'd say punt it, and let's get that done in a separate SRFI, which can contain language mentioning how fluids interact with thread systems, explicitly citing SRFI-18 by way of example. But put into SRFI-18 some *generic* language saying that dynamic binding facilities should be part of the continuation, hence threads pick up a new dynamic env on a continuation throw. How do you like that? -Olin