[racket] Saving and restoring many parameters

From: Neil Toronto (neil.toronto at gmail.com)
Date: Wed Oct 19 14:39:17 EDT 2011

On 10/19/2011 11:39 AM, Neil Toronto wrote:
> On 10/19/2011 10:31 AM, John Clements wrote:
>> On Oct 19, 2011, at 9:29 AM, John Clements wrote:
>>> On Oct 19, 2011, at 4:03 AM, Robby Findler wrote:
>>>> (I'm sorry if you got this message already; I thought I sent it
>>>> already but I don't see it.)
>>>> What about the current-output/error-port? what about the
>>>> current-namespace? current-custodian?
>>>> There are lots of parameters that affect core functions in subtle ways
>>>> and if you do something like this in plot, it seems like it could lead
>>>> to serious confusion someday. Also, it can introduce leaks.
>>> +1. I think this is not not not a good idea.
>>> Robby's solution requires you to make one list of all of the
>>> plot-related parameters, which looks to me like the "right" amount of
>>> work.
>>> Furthermore, it has the unpleasant characteristic that when it
>>> breaks, it will be exposed in an unwanted change to a parameter that
>>> will likely be entirely unrelated to plot. Tracking this down will be
>>> horrible, and the axe-wielding murderer of legend will be very
>>> unhappy when he (or she?) finally gets to your doorstep.
>> Dangling pronoun. Of course, I meant to say
>> "Furthermore, [your solution] has the unpleasant characteristic..."
> Look, as long as it's not Richard Stallman with the ax...
> If I spawn a render thread that inherits the parent thread's parameters,
> won't things like current-namespace and current-custodian have the right
> values?
> It's starting to look like that is the solution that is the most
> maintainable and the least work. And it still allows users to
> parameterize the functions they plot. If something breaks, it's not my
> fault, because spawning a thread that waits on a channel for a "draw
> now!" command, and then draws on a dc, should just work, right?
> (There shouldn't be any contention over the dc because I'd have the
> slideshow thread wait on an "all finished" reply over the channel.)

For concreteness, here's what I've got now:

;; f : any -> any
;; Returns a wrapper for 'f' that preserves most of the parameter values
;; in the dynamic extent where 'parameterize-procedure' is applied.
(define (parameterize-procedure f)
   (struct apply-thread (channel thread) #:transparent)
   (struct apply-command (kws kw-values rest) #:transparent)
   (struct exception-response (exception) #:transparent)
   (struct values-response (values) #:transparent)
   ;; A synchronous channel for commands and responses
   (define ch (make-channel))
   ;; The command loop
   (define (command-loop)
     (match-define (apply-command kws kw-values rest) (channel-get ch))
     (with-handlers ([(λ (e) #t)
                      (λ (e) (channel-put ch (exception-response e)))])
       (channel-put ch (call-with-values
                        (λ () (keyword-apply f kws kw-values rest))
                        (λ vals (values-response vals)))))
   ;; Save the thread in a struct so it'll get closed over
   (define th (apply-thread ch (thread command-loop)))
   ;; Return the wrapper
    (lambda (kws kw-args . rest)
      (match-define (apply-thread ch _) th)
      (channel-put ch (apply-command kws kw-args rest))
      (match (channel-get ch)
        [(exception-response e)  (raise e)]
        [(values-response vals)  (apply values vals)]))))

I can't decide whether it's ugly or beautiful. It works great, though.

Neil T

Posted on the users mailing list.