Hello everyone,

Thanks for all the responses, they have been very clarifying.

I'd like to add the following for your consideration of using parameters.

When using the plot package, I really like to setup common parameters using 
parameterize and then tweak others using the named parameters in the 
function call,

such as:

(parameterize ([surface-color 'blue])
(plot3d (list (surface3d (λ (x y) (+ (sqr x) (sqr y))) -1 1 -1 1
                           #:label "z = x^2 + y^2")
                (surface3d (λ (x y) (- (+ (sqr x) (sqr y)))) -1 1 -1 1
                           #:line-color 4
                           #:label "z = -x^2 - y^2"))))

where surface-color is set for all, but line-color is modified in the 
second plot.

One thing that I believe adds friction to the usability is the fact that 
the name of the global parameter, surface-color for example,
is usually different to the named parameter in the function; for the case 
of surface3d, surface-color is mapped to #:color and in the case
of parametric3d line-color is also mapped to #:color.

This makes sense because the parameters are global, so the chances of 
colliding with a parameter from another package is high.

I wonder if an approach like the one used in Mathematica could work here, 
where it is possible to modify the defaults
of a function using SetOptions[fun, opt1->value ...], which would be 
equivalent to calling (parameter new-value), and then override that setting 
by calling fun[ params , opt1->value1 ...],
avoiding the use of a global parameter. I think the function along with its 
parameters could be stored in a struct, and then prop:procedure could be 
used to hide the fact that it's a struct.


Carlos

On Friday, August 3, 2018 at 3:36:14 PM UTC-4, Alexis King wrote:
>
> Maybe this isn’t really a direct response to the direction this thread 
> has taken, but given the question proposed in the original message, I 
> think it’s relevant to share a particular design pattern for parameters 
> that seems to work well. In a number of different APIs provided by 
> Racket, a function’s behavior can be controlled by an optional argument 
> (often a keyword argument), and that argument’s default value is the 
> value of a parameter. For example, the eval function accepts an optional 
> namespace as its second argument, and if it isn’t supplied, it uses 
> (current-namespace). 
>
> From a user’s point of view, this is the best of both worlds, since they 
> can parameterize a set of function calls in a single parameterize block 
> without needing to thread an argument everywhere, taking advantage of 
> parameters’ capability for implicit configuration, but they can also 
> pass an argument directly if they’re only calling a function once or 
> twice. However, this *also* has benefits for implementors, since it 
> sidesteps the inability to close over the value of the current 
> parameterization since the value becomes entirely lexical when it is 
> bound to the formal argument of the function. 
>
> For a simple example, consider a contrived function configured by a 
> parameter: 
>
>   (define current-summand (make-parameter 0)) 
>
>   (define (make-adder) 
>     (lambda (n) (+ (current-summand) n))) 
>
> This is a silly function, but one can see how it is broken in the way 
> Alex describes (which he shows can happen in more realistic situations). 
> The intent is to close over the current value of (current-summand) when 
> make-adder is invoked, but a naïve implementation doesn’t capture the 
> current value and always produces the same function. Adjusting this 
> function that the summand is provided as an optional argument both 
> improves the user-facing API and fixes the bug: 
>
>   (define (make-adder [summand (current-summand)]) 
>     (lambda (n) (+ summand n))) 
>
> This also ensures that if a parameter-configured function defers to 
> other functions as part of its implementation, it will pass the value 
> lexically rather than dynamically by explicitly providing the optional 
> argument, so the dynamic configuration is effectively “terminated” at 
> the API boundary. 
>
> Now, this isn’t to say this technique doesn’t have some drawbacks. For 
> one, it means API users get to benefit from the dynamic configuration, 
> but API implementors do not, and in fact have to do extra work. 
> Furthermore, one might find the very existence of a “design pattern” in 
> Racket to be suspect, given we generally try to avoid boilerplate 
> patterns in favor of new linguistic abstractions. Maybe this hints at 
> some shortcoming in parameters that would be better solved by a new 
> language feature, but I can’t immediately come up with one. Perhaps 
> others have better ideas than I do in that department. 
>
> > On Aug 2, 2018, at 12:24, 'John Clements' via Racket Users 
> > <racket...@googlegroups.com <javascript:>> wrote: 
> > 
> > I hate to turn a little question into a big one, but… are parameters 
> > the right choice, here? It seems to me that optional parameters would 
> > be more suitable. 
> > 
> > Unfortunately, I’ve been on the other side of this fence, too: 
> > parameters are vastly more convenient for implementors than adding 
> > optional parameters to every one of the internal calls. This certainly 
> > came up for me in the construction of a CSV writing library. 
> > 
> > I can imagine a bunch of programming patterns that might assist this; 
> > the most obvious one would be an object-like metaphor where parameter 
> > values are represented as an object to which calls are made. Do others 
> > have ideas on a “best practice” for this situation and others like it? 
> > 
> > John 
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to