[racket] Saving and restoring many parameters
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)))))
(command-loop))
;; Save the thread in a struct so it'll get closed over
(define th (apply-thread ch (thread command-loop)))
;; Return the wrapper
(make-keyword-procedure
(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