[plt-scheme] Re: Parameterizing Modules with variables

From: Eli Barzilay (eli at barzilay.org)
Date: Mon Apr 21 18:41:46 EDT 2003

On Apr 21, Ed Cavazos wrote:
> So I read about parameters and they are "thread specific". I can of
> course see how this is a virtue in many cases, and a benfit over
> variables. However, in the above case, after spawning off a thread I
> lose contact with those parameters from my REPL. Right now I'm
> thinking that I should launch a GUI from within the thread which
> will be my tether to the parameters. Or perhaps a way to launch a
> REPL that introspects into the environment of a spawned thread.

I don't think there's anything wrong with such global variables,
especially if you mark them with **'s -- after all, they do exactly
what you want them to do, which is share modifiable information
between threads...  (You might want to add a semaphore protection if
there's a way to get to a bogus configuration.)

If you still insist on a parameter, then one option would be to have a
parameter-like function that will access a global but will be shared
since it will not be a parameter, for example, one that has a
parameter-like-function inside it.  I had a similar problem with my
webserver -- I wanted to have "special" parameters that when they are
created, they are shared among all sub-threads.  This is the code that
I use:

(define (make-connection-parameter . default)
  ;; This returns a parameter-like function that uses a parameter to store an
  ;; actual value-function and use that.  The effect is that once we set the
  ;; value, all created threads will share that value.  Note that since
  ;; check-parameter-procedure accept any function of 0/1 args, this will also
  ;; behave with parameterize.
  (define param (make-parameter #f))
  (define (connection-parameter . args)
    (let ((p (param)))
       ((and p (null? args)) (p))
       (p (p (car args)))
       ((null? args)
        (if (null? default)
          (error 'connection-parameter "accessing uninitialized parameter")
          (car default)))
       ;; don't create a parameter that will be used in the global thread
       ((eq? (current-thread) *toplevel-thread*) (set! default args))
       (else (param
              (let ((v (1st args)))
                (define (p . args)
                  (if (null? args) v (set! v (car args))))
                (if (promise? v)
                  ;; this is so only initial promises are possible and nothing
                  ;; else gets the penalty of `promise?'
                  (lambda args (set! v (force v)) (param p) (apply p args))

But it is very tricky to get the details right, and I'm not sure how
stable the whole thing is.  I think that for you a global is enough.

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!

Posted on the users mailing list.