On 31-Jan-09, at 11:44 PM, lowly coder wrote:
Great, the following works:
cat test.scm (define (foo x) (* x 2))
(define (g x) (foo x))
(pp (g 2)) (pp (let ((old-func '())) (dynamic-wind (lambda () (set! old-func foo) (set! foo (lambda (x) (* x 3)))) (lambda () (g 2)) (lambda () (set! foo old-func)))))
(pp (g 2))
4 6 4
two questions:
- can anything go wrong with variable capture / aliasing?
[intuitively, I believe no, so long as I don't use 'old-func' in my thunk 2) is there a more elegant/idiomatic way to do this?
In terms of elegance I prefer this (which eliminates all variable capture problems):
(let ((thunk (lambda () (g 2))) (new-foo (lambda (x) (* x 3))) (old-foo foo)) (dynamic-wind (lambda () (set! foo new-foo)) thunk (lambda () (set! foo old-foo))))
But once again this will not work right if multiple threads are dynamically scoping foo simultaneously, but the parameterize based approach will work fine.
Marc
Afficher les réponses par date
Re problems in multithreaded programs:
The dynamic environment is composed of two parts: the "local dynamic environment" and the "global dynamic environment". There is a single global dynamic environment, and it is used to lookup parameter objects that can't be found in the local dynamic environment.
is that the main reason? that with the parameter method, i'm changing the 'local env' (which each thread has it's own) whereas with the dynamic-wind method, I'm setting a var in the global env (which all the threads share)
On Sat, Jan 31, 2009 at 9:05 PM, Marc Feeley feeley@iro.umontreal.cawrote:
On 31-Jan-09, at 11:44 PM, lowly coder wrote:
Great, the following works:
cat test.scm (define (foo x) (* x 2))
(define (g x) (foo x))
(pp (g 2)) (pp (let ((old-func '())) (dynamic-wind (lambda () (set! old-func foo) (set! foo (lambda (x) (* x 3)))) (lambda () (g 2)) (lambda () (set! foo old-func)))))
(pp (g 2))
4 6 4
two questions:
- can anything go wrong with variable capture / aliasing? [intuitively, I
believe no, so long as I don't use 'old-func' in my thunk 2) is there a more elegant/idiomatic way to do this?
In terms of elegance I prefer this (which eliminates all variable capture problems):
(let ((thunk (lambda () (g 2))) (new-foo (lambda (x) (* x 3))) (old-foo foo)) (dynamic-wind (lambda () (set! foo new-foo)) thunk (lambda () (set! foo old-foo))))
But once again this will not work right if multiple threads are dynamically scoping foo simultaneously, but the parameterize based approach will work fine.
Marc
On 1-Feb-09, at 12:18 AM, lowly coder wrote:
Re problems in multithreaded programs:
The dynamic environment is composed of two parts: the "local
dynamic environment" and the "global dynamic environment". There is a single global dynamic environment, and it is used to lookup parameter objects that can't be found in the local dynamic environment.
is that the main reason? that with the parameter method, i'm changing the 'local env' (which each thread has it's own) whereas with the dynamic-wind method, I'm setting a var in the global env (which all the threads share)
In a way yes. Except the global variables are not part of the global dynamic environment. They are part of the global lexical environment. But you are correct that the problem is that they are shared by all threads instead of each thread having his own local bindings.
Marc
Date: Sun, 1 Feb 2009 00:05:49 -0500 From: Marc Feeley feeley@iro.umontreal.ca
(let ((thunk (lambda () (g 2))) (new-foo (lambda (x) (* x 3))) (old-foo foo)) (dynamic-wind (lambda () (set! foo new-foo)) thunk (lambda () (set! foo old-foo))))
This idiom doesn't respect assignments to FOO that happen outside the dynamic extent of the call to THUNK. If control exits the extent, FOO is set to another value outside the extent, and control re-enters the extent, then when control exits again, FOO will have its value reverted to whatever it was when control first entered the extent, forgetting its current value outside the extent. Thus the dynamic binding is not transparent to the enclosing extent. To make it transparent, write:
(let ((new-foo ...) (old-foo #f)) (dynamic-wind (lambda () (set! old-foo foo) (set! foo new-foo)) thunk (lambda () (set! foo old-foo) (set! old-foo #f))))
Date: Sun, 1 Feb 2009 15:20:07 -0500 From: Taylor R Campbell campbell@mumble.net
(let ((new-foo ...) (old-foo #f)) (dynamic-wind (lambda () (set! old-foo foo) (set! foo new-foo)) thunk (lambda () (set! foo old-foo) (set! old-foo #f))))
Oops. This idiom is wrong, too. (It has the same issue as I described but for assignments that happen during the inner extent.) Here's what you really want, to dynamically bind FOO to <value> using DYNAMIC-WIND:
(let ((outer-foo #f) (inner-foo <value>)) (dynamic-wind (lambda () (let ((outer foo) (inner inner-foo)) (set! inner-foo #f) (set! foo inner) (set! outer-foo outer))) thunk (lambda () (let ((inner foo) (outer outer-foo)) (set! outer-foo #f) (set! foo outer) (set! inner-foo inner)))))
In MIT Scheme, where (SET! X Y) returns the old value of X, this is much more concisely written
(let ((outer-foo #f) (inner-foo <value>)) (dynamic-wind (lambda () (set! outer-foo (set! foo (set! inner-foo #f)))) thunk (lambda () (set! inner-foo (set! foo (set! outer-foo #f))))))