lowly coder | 1 Feb 2009 01:49

dynamic scope

is there anyway i can obtain dynamic scoping in gambit? lexically scoping is really cool, and I want it as the default behavior; i just want the ability to go:

(define (foo x) (* x 2))

(define (g x) (foo x))

(pp (list (g 1) (dynamic-let ( (foo (lambda (x) (* x 3)))) (g 1))))

to get me:

(2 3)

_______________________________________________
Gambit-list mailing list
Gambit-list <at> iro.umontreal.ca
https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Marc Feeley | 1 Feb 2009 02:11
Picon
Gravatar

Re: dynamic scope


On 31-Jan-09, at 7:49 PM, lowly coder wrote:

> is there anyway i can obtain dynamic scoping in gambit? lexically  
> scoping is really cool, and I want it as the default behavior; i  
> just want the ability to go:
>
> (define (foo x) (* x 2))
>
> (define (g x) (foo x))
>
> (pp (list (g 1) (dynamic-let ( (foo (lambda (x) (* x 3)))) (g 1))))
>
> to get me:
>
> (2 3)

This is the way you can do dynamic scoping in Gambit (and other  
Schemes too):

(define foo (make-parameter (lambda (x) (* x 2))))

(define (g x) ((foo) x))

(pp (list (g 1) (parameterize ((foo (lambda (x) (* x 3)))) (g 1))))

You can also use dynamic-wind to simulate dynamic scoping but it does  
not work properly with threads.

Marc
lowly coder | 1 Feb 2009 03:05

Re: dynamic scope

Cool, thanks!

The 'problem' I see with this, is that I have to know before hand that I want this variable to be dynamic. The use case here is:

I'm looking at an existing code base, it has 'foo', which depends on 'bar'.

I want to call existing function 'foo' with a new definition of 'bar'.

Is there no other way than to edit the definition of bar and make it a parameter?

Thanks!

On Sat, Jan 31, 2009 at 5:11 PM, Marc Feeley <feeley <at> iro.umontreal.ca> wrote:

On 31-Jan-09, at 7:49 PM, lowly coder wrote:

is there anyway i can obtain dynamic scoping in gambit? lexically scoping is really cool, and I want it as the default behavior; i just want the ability to go:

(define (foo x) (* x 2))

(define (g x) (foo x))

(pp (list (g 1) (dynamic-let ( (foo (lambda (x) (* x 3)))) (g 1))))

to get me:

(2 3)

This is the way you can do dynamic scoping in Gambit (and other Schemes too):

(define foo (make-parameter (lambda (x) (* x 2))))


(define (g x) ((foo) x))

(pp (list (g 1) (parameterize ((foo (lambda (x) (* x 3)))) (g 1))))

You can also use dynamic-wind to simulate dynamic scoping but it does not work properly with threads.

Marc


_______________________________________________
Gambit-list mailing list
Gambit-list <at> iro.umontreal.ca
https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Marc Feeley | 1 Feb 2009 03:10
Picon
Gravatar

Re: dynamic scope


On 31-Jan-09, at 9:05 PM, lowly coder wrote:

> Cool, thanks!
>
> The 'problem' I see with this, is that I have to know before hand  
> that I want this variable to be dynamic. The use case here is:
>
> I'm looking at an existing code base, it has 'foo', which depends on  
> 'bar'.
>
> I want to call existing function 'foo' with a new definition of 'bar'.
>
> Is there no other way than to edit the definition of bar and make it  
> a parameter?

Yes... dynamic-wind.

Marc
|/|/ Bendick | 1 Feb 2009 05:59
Picon
Gravatar

Re: The future of Gambit

I've also wanted to fix a bug myself in Gambit several times but found
the code to be a bit too mysterious. I agree that if one subsystem's
coding convention's could be fully explained, this might crack the
whole thing open. I know writing good docs is hard, perhaps it would
be easier to convince *someone* to get up and start speaking in front
of a camera and then just put it online. I think most people who are
interested in getting some work done on the gambit internals really
just want to know 'the big picture', namely.. what are the subsystems,
how do they fit together, and what are the common coding techniques
that make this happen.

On Wed, Jan 14, 2009 at 10:41 AM, Bradley Lucier <lucier <at> math.purdue.edu> wrote:
>
> On Jan 14, 2009, at 10:27 AM, Marc Feeley wrote:
>
>>> I've studied the Gambit source code a bit, and even made some
>>> contributions over the years, but Marc's programming style is
>>> something I have not seen elsewhere---highly macroized and layered,
>>> there are patterns in the coding techniques but not ones that I've
>>> been able to unravel in general.    Perhaps one way to help new
>>> developers get into Gambit would be fore Marc to take a subsystem and
>>> write down an explanation of how the macros and layers of code for
>>> types, exceptions, constructors, functions, ... of that subsystem
>>> work.  (Christian Jaeger seems to have had some success in doing
>>> this, but it would be good to have an explanation of how Marc sees
>>> the construction of subsystems of the runtime.)  Just to get an idea
>>> of Marc's programming style would allow others to divine more easily
>>> the structure of the code.
>
> Marc:
>
> Thank you for your reply.
>
> I'm thinking something along the lines of Shriram's talk "The Swine
> before Perl", which goes through an example of how to program finite-
> state automata using define-syntax macros.  To object to no
> documentation is not to demand full documentation---I've included one
> of my paragraphs above which explains that it would be nice to see how
> you think of programming.  Pick a subsystem of the runtime or of the
> compiler (the register allocator, beta-reduction, lambda-lifting, one
> of them), explain what the layers are, how and why you do it.  People
> would learn from it (I think I would be a better programmer if I
> understood it).
>
> Brad
> _______________________________________________
> Gambit-list mailing list
> Gambit-list <at> iro.umontreal.ca
> https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
>

--

-- 
|/|/ Bendick
Marc Feeley | 1 Feb 2009 06:05
Picon
Gravatar

Re: dynamic scope


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:
> 1) 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
lowly coder | 1 Feb 2009 06:09

reading list of symbols defined in top level

suppose I have test.scm:

(define (foo ...) ...)
(define (bar ...) ...)
(define (yay ...) ...)

(some-magical-funcion) --> '(bar foo yay) # is this possible?

basically, I want to have some function I can call to get a list of all symbols defined in the current top level

_______________________________________________
Gambit-list mailing list
Gambit-list <at> iro.umontreal.ca
https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
lowly coder | 1 Feb 2009 06:18

Re: dynamic scope

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 <at> iro.umontreal.ca> wrote:

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:
1) 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


_______________________________________________
Gambit-list mailing list
Gambit-list <at> iro.umontreal.ca
https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Marc Feeley | 1 Feb 2009 06:29
Picon
Gravatar

Re: reading list of symbols defined in top level


On 1-Feb-09, at 12:09 AM, lowly coder wrote:

> suppose I have test.scm:
>
> (define (foo ...) ...)
> (define (bar ...) ...)
> (define (yay ...) ...)
>
> (some-magical-funcion) --> '(bar foo yay) # is this possible?
>
> basically, I want to have some function I can call to get a list of  
> all symbols defined in the current top level

Depends what you mean by "the current top level".  Anyway, the code  
below may be close to what you want:

(##namespace ("foo#"))
(##include "~~lib/gambit#.scm")

(define (id x) x)
(define (square x) (* x x))

(##namespace (""))

(define (global-vars-in-namespace ns)

   (define (symbol-table-≥list st)
     (apply append
            (map (lambda (s)
                   (let loop ((s s) (lst '()))
                     (if (symbol? s)
                         (loop (##vector-ref s 2) (cons s lst))
                         (reverse lst))))
                 (vector->list st))))

   (define (procedure-in-namespace? s)
     (let ((len (string-length ns))
           (str (symbol->string s)))
       (and (>= (string-length str) len)
            (equal? (substring str 0 len) ns)
            (let ((val (##global-var-ref (##make-global-var s))))
              (procedure? val)))))

   (define (keep keep? lst)
     (cond ((null? lst)       '())
           ((keep? (car lst)) (cons (car lst) (keep keep? (cdr lst))))
           (else              (keep keep? (cdr lst)))))

   (keep procedure-in-namespace?
         (symbol-table-≥list (##symbol-table))))

(pp (global-vars-in-namespace "foo#")) ;; prints: (foo#square foo#id)
Marc Feeley | 1 Feb 2009 06:31
Picon
Gravatar

Re: dynamic scope


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

Gmane