Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling flexible arguments in Mathematica functions

This is an offshoot and extension of: Is it safe to turn off Pattern::patv?

Many built-in Mathematica functions allow flexible arguments. In user-defined functions I have been using Alternatives for this purpose, but comments and answers to the question referenced indicate that this is at least nonstandard, and perhaps undesirable.

Let me define a dummy function foo as an example.

Off[Pattern::patv]

p = {_?NumericQ, _?NumericQ};

foo[
  {x : p ..} | x : p,
  {y__} | y__,
  ops : OptionsPattern[]
] /; Max[y] <= 10  :=  bar[#, y, ops] & /@ {x}

foo accepts, in order:

  • an object matching patten p, or a list of such objects.
  • a set of implicitly numeric objects with a maximum value of 10, either as a list or a sequence of arguments (as written these objects themselves could be numeric lists with a maximum value of 10)
  • options matching OptionsPattern[]

If any of these conditions are not met, foo[args] is returned unevaluated.

The two pattern using Alternatives (|) are the most common cases, but they are not exclusive.

I struggle to see how foo should best be implemented.

  • What is the canonical way to accomplish this?

  • What are its advantages over using Alternatives?

  • Is it objectively easier to read?

like image 681
Mr.Wizard Avatar asked Dec 15 '11 13:12

Mr.Wizard


Video Answer


1 Answers

I believe that there are three canonical ways of dealing with flexible arguments:

  1. anything goes: f[x_],
  2. multiple forms: f[{x : p ..}] and f[x:p], where one calls the other, and
  3. alternation: f[{x : p ..} | x : p].

The primary difference is where you deal with the added complexity of flexible arguments. Each can have its advantages.

The primary advantage of anything goes is simplicity in creating the acceptable patterns, but this leaves the processing to the internals of the function which increases its complexity. See the ErrorBarPlots .m file for a good example of this. Ultimately, though, ErrorListPlot relies on the second method hidden behind the facade of the first method.

The multiple forms method pushes the complexity onto the dispatcher in choosing the correct alternative. It has the simplest functional form as one form usually calls another form with the "correct" layout of the data. The difficulty with this method is the exponential growth of function specifications with the number of parameters with alternatives. This can be limited by adopting a hybrid approach, like that found in ErrorListPlot.

Alternation has the most complex pattern form, and may require special processing to extract the alternatives similar to anything goes. Also, the patterns themselves can be more difficult to construct, and because of the potential for extra processing, this method should be used least often of the three. However, in some cases, like in your code, this method can be the most straightforward implementation.

like image 122
rcollyer Avatar answered Sep 28 '22 11:09

rcollyer