Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Passing function arguments as lists of replacement

1 view
Skip to first unread message

Leo Alekseyev

unread,
Nov 7, 2009, 6:44:24 AM11/7/09
to
This is certainly one option, but does it have any benefits over the
list of string replacement rules?..

I recently started using both the options pattern _and_ a replacement
list. The actual functions I'm working with look something like

foo[x_,y_,parameters_,OptionsPattern[]],

where x and y are bona fide dependent variables, parameters is a list
of fixed constants pertinent to the system (provided as replacement
rules of the form, e.g. {"a"->1,...}, and OptionsPattern[] conveys
certain options pertaining to the computation itself, e.g.
{AvoidDivideByZero->True}

So far it seems like a sensible approach, but I am still wondering if
other people do similar things in their code.

--Leo

On Fri, Nov 6, 2009 at 8:57 AM, David Park <djm...@comcast.net> wrote:
> Use the newer Version 6 Options facilities.
>
> ClearAll[foo]
> Options[foo] = {a -> 0, b -> 0, c -> 0};
> SyntaxInformation[foo] = {"ArgumentsPattern" -> {OptionsPattern[]}};
> foo[OptionsPattern[]] :=
> Module[
> {aval = OptionValue[a],
> bval = OptionValue[b],
> cval = OptionValue[c]},
> {aval, bval, cval}]
>
> foo[a -> 1, b -> 2]
> {1, 2, 0}
>
> Then try typing:
>
> foo[a -> 1, q -> 2]
>
>
> David Park
> djm...@comcast.net
> http://home.comcast.net/~djmpark/
>
>
> From: dnquark [mailto:dnq...@gmail.com]
>
>
> I wish to (a) avoid having to pass a dozen parameters to a function
> and have to deal with remembering which goes where and (b) retain the
> flexibility in terms of adding new parameters. It seems that a good
> solution would be to pass my parameters as a structure with named
> fields (this is how I do it in another system). In Mathematica, I came=
up
> with something like this:
>
> foo[paramList_] := Module[{a,b,c},
> {a,b,c} = {"a","b","c"}/.paramList;
> {a,b,c}
> ]
> sample usage: e.g. foo[{"a"->1,"b"->2}]
>
> My question to the group: is this a good solution? Are there better
> ways to achieve my goals?..
> Thanks,
> --Leo
>
>
>

David Park

unread,
Nov 7, 2009, 6:47:21 AM11/7/09
to
Use the newer Version 6 Options facilities.

ClearAll[foo]
Options[foo] = {a -> 0, b -> 0, c -> 0};
SyntaxInformation[foo] = {"ArgumentsPattern" -> {OptionsPattern[]}};
foo[OptionsPattern[]] :=
Module[
{aval = OptionValue[a],
bval = OptionValue[b],
cval = OptionValue[c]},
{aval, bval, cval}]

foo[a -> 1, b -> 2]
{1, 2, 0}

Then try typing:

foo[a -> 1, q -> 2]


From: dnquark [mailto:dnq...@gmail.com]


I wish to (a) avoid having to pass a dozen parameters to a function
and have to deal with remembering which goes where and (b) retain the
flexibility in terms of adding new parameters. It seems that a good
solution would be to pass my parameters as a structure with named

fields (this is how I do it in another system). In Mathematica, I came up

David Park

unread,
Nov 7, 2009, 6:49:04 AM11/7/09
to
Leo,

This is certainly an interesting question and it is very worthwhile writing
routines that make it easy to use Mathematica for your particular purposes.
I call them convenience routines. There may be many ways to do this and you
may get many suggestions, including dynamic input. Here is one other
possibility with a sample foo that has most of the features that you want.

ClearAll[foo]
Options[foo] = {PrintParameters -> False};
foo[parameters_List: {1, 2, 3}, OptionsPattern[]][x_, y_] :=
Module[{a, b, c},
{a, b, c} = parameters;
If[OptionValue[PrintParameters], Print[{a, b, c}]];
a x + b y + c x y
]

Now we could just use this in a normal manner:

foo[][x, y]

foo[PrintParameters -> True][x, y]

foo[{3, 2, 1}][x, y]

But if you wanted to actually edit the input parameters, and maybe if you
had a longer list of parameters, you could first type the following
statement:

With[
{a = 1,(* Temperature Kelvin *)
b = 2, (* Velocity m/s *)
c = 3}, (* Altitude meters *)
foo[{a, b, c}][x, y]]

Now open up the cell to get the underlying expression. (Shift-Ctrl-E, or
Menu -> Cell -> Show Expression) Copy the Cell expression. Then paste it in
the following expression:

fullfoo :=
CellPrint[Cell[BoxData[RowBox[{"With", "[", "
", RowBox[{RowBox[{"{",
RowBox[{RowBox[{"a", "=", "1"}], ",",
RowBox[{"(*", " ", RowBox[{"Temperature", " ", "Kelvin"}],
" ", "*)"}], "
", RowBox[{"b", "=", "2"}], ",", " ",
RowBox[{"(*", " ",
RowBox[{"Velocity", " ", RowBox[{"m", "/", "s"}]}], " ",
"*)"}], "
", RowBox[{"c", "=", "3"}]}], "}"}], ",", " ",
RowBox[{"(*", " ", RowBox[{"Altitude", " ", "meters"}], " ",
"*)"}], "
",
RowBox[{RowBox[{"foo", "[",
RowBox[{"{", RowBox[{"a", ",", "b", ",", "c"}], "}"}],
"]"}], "[", RowBox[{"x", ",", "y"}], "]"}]}], "]"}]],
"Input"]]


Now, if you evaluate fullfoo, you will obtain the initial expression with
the default values of the parameters and annotation. One can then just edit
whichever values one wishes, or put the option into foo, and evaluate.

So, you can have it both ways, short if you set the parameters once and for
all, and long if you want to play with the parameters. The long way is also
nice if you are writing it for someone else who doesn't know Mathematica
that well and you don't know what changes they may wish to make.

From: leo.al...@gmail.com [mailto:leo.al...@gmail.com] On Behalf Of
Leo Alekseyev


This is certainly one option, but does it have any benefits over the
list of string replacement rules?..

I recently started using both the options pattern _and_ a replacement
list. The actual functions I'm working with look something like

foo[x_,y_,parameters_,OptionsPattern[]],

where x and y are bona fide dependent variables, parameters is a list
of fixed constants pertinent to the system (provided as replacement
rules of the form, e.g. {"a"->1,...}, and OptionsPattern[] conveys
certain options pertaining to the computation itself, e.g.
{AvoidDivideByZero->True}

So far it seems like a sensible approach, but I am still wondering if
other people do similar things in their code.

--Leo

On Fri, Nov 6, 2009 at 8:57 AM, David Park <djm...@comcast.net> wrote:

Leonid Shifrin

unread,
Nov 8, 2009, 6:50:30 AM11/8/09
to
Hi Leo,

The advantage of using Options mechanism is the increased safety during the
pattern-matching, since built-ins such as OptionValue - OptionsPattern, or
older OptionQ provide a sort of a type-check. The newer constructs
OptionValue - OptionsPattern provide more safety than OptionQ, since
OptionValue inspects a list of global Options to make sure that the passed
option is known to the function. The older OptionQ seems however easier to
understand since it is based only on the standard pattern-matching and isn't
directly related to any of the global properties. Whether or not you want
this extra safety provided by any of these constructs is up to you, but my
guess is that most people find it useful, especially for larger projects.

One reason why these type checks are really useful is that often options are
passed as parameters by functions in a chain-like manner, filtered, etc.,
so without such checks some of the pattern-matching errors would be very
hard to catch since they would be causing harm "far away" from the place of
their origin.

If you want to maintain a logical separation between options and named
parameters, here a a few possibilities. First is to use a kind of
SubValue-based definition, like this:

ClearAll[f];
parameters[f] = {"npar1" -> 1, "npar2" -> 2, "npar3" -> 3};
Options[f] = {"option1" -> 4, "option2" -> 5};
f[a_, b_, pars___?OptionQ][opts___?OptionQ] :=
Module[{npar1, npar2, npar3, option1, option2},
{npar1, npar2,
npar3} = {"npar1", "npar2", "npar3"} /. Flatten[{pars}] /.
parameters[f];
{option1, option2} = {"option1", "option2"} /. Flatten[{opts}] /.
Options[f];
Print["Positional paramaters: ", a, " ", b,
"\n Named parameters ", npar1, " ", npar2, " ", npar3,
"\n Options ", option1, " ", option2]]

The usage will be something like

In[1] :=
f[a,b,"npar2"-> 10]["option1"->20]

Positional paramaters: a b
Named parameters 1 10 3
Options 20 5

Here I introduced a new (user-defined) container <parameters>, to store
defaults for the named parameters. This uses the old OptionQ option-testing
predicate. You could also use OptionsPattern:

ClearAll[ff];
Options[ff] = {"option1" -> 4, "option2" -> 5, "npar1" -> 1,
"npar2" -> 2, "npar3" -> 3};


ff[a_, b_, npars : OptionsPattern[]][opts : OptionsPattern[]] :=
Module[{npar1, npar2, npar3, option1, option2},
{npar1, npar2, npar3} =
OptionValue[ff, {npars}, #] & /@ {"npar1", "npar2", "npar3"};
{option1, option2} =
OptionValue[ff, {opts}, #] & /@ {"option1", "option2"};
Print["Positional paramaters: ", a, " ", b,
"\n Named parameters ", npar1, " ", npar2, " ", npar3,
"\n Options ", option1, " ", option2]]

But here, to take advantage of OptionValue, we have to store all defaults in
Options[ff]. Of course you can also mix things, keeping OptionsPattern but
not using OptionValue for your named parameters, and instead using something
like <parameters> and the old option-passing mechanism.

You can also use a different signature - for example make your named
arguments be the optional very first argument and options - the last one:

g[npars : OptionsPattern[], a_, b_, opts : OptionsPattern[]] :=...

This lets you avoid SubValues if for some reason you don't want to use them.
In this case however, you must make sure that your first normal parameter
(a_ here) does not match the option pattern, to avoid ambiguities. Note that
if you use named parameters next to options in your arguments list, you may
end up with ambigous pattern-matching and some of your parameters may be
interpreted as options or vice versa.

Of course, there are plenty of other possible solutions. For example, wrap
named parameters in some container to which you give a special meaning, like
<namedParameters> below

g[a_, b_,namedParameters[npars : OptionsPattern[]], opts : OptionsPattern[]]
:=...

and keep the argument namedParameters[] present but empty if you don't want
to pass any named parameters explicitly. The latter inconvenience can be
removed by overloading a function like this:

g[a_, b_, opts : OptionsPattern[]] :=.g[a,b,namedParameters[],opts],

which lets you use the shorter form if no named parameters need to be
passed.

Yet another possibility is to make a special option called say
"namedParameters", and pass it whenever you need to pass some parameters,
like

g[a,b,"namedParameters"->{"npar1"->value1,...}]

This has the advantage of both using the standard mechanism and maintaining
the logical separation between options and parameters, but the "type-check"
for the list of parameters is no longer there (you can of course implement
it with some extra code).

The final comment is that whatever style you choose, it will start to pay
off when there will be many functions which you will treat consistently
according to this style, and it should be as "mindless" to use as possible.
Using the standard mechanisms has many advantages, such as a better
integration with both the exisitng and not yet existing functionality, to
name just one.

Hope this helps.

Regards,
Leonid

> > http://home.comcast.net/~djmpark/ <http://home.comcast.net/%7Edjmpark/>


> >
> >
> > From: dnquark [mailto:dnq...@gmail.com]
> >
> >
> > I wish to (a) avoid having to pass a dozen parameters to a function
> > and have to deal with remembering which goes where and (b) retain the
> > flexibility in terms of adding new parameters. It seems that a good
> > solution would be to pass my parameters as a structure with named

> > fields (this is how I do it in another system). In Mathematica, I came=

0 new messages