17
$\begingroup$

I am trying to reproduce the API of a function (written in R) that accepts an arbitrary number of arguments and handles it the same way as it would handle a single argument that is a list of different data sets.

Is there a Mathematica idiom that allows a function to be defined so that:

f[ arg1, arg2, ..., argN ]

behaves the same as

f[ {arg1, arg2, ..., argN} ]

?

$\endgroup$
1
  • 20
    $\begingroup$ You could just write f[args___]:= f[{args}] and then provide the definition for f[{arg1_, arg2_,...}]. $\endgroup$
    – Andy Ross
    Commented Dec 5, 2012 at 3:54

2 Answers 2

17
$\begingroup$

As described by Andy Ross in a comment, you can make a definition that preprocesses the argument(s) into a canonical form. Turning his example around simply to illustrate flexibility:

f[{args__}] := f[args]

f[args__] := Multinomial[args] / Plus[args]

f[{12, 7, 3}] == f[12, 7, 3]

True

This method is useful for more complicated preprocessing, but in simple cases such as this it is often easier to use Alternatives:

g[{args__} | args__] := Multinomial[args]/Plus[args]

g[{12, 7, 3}] == g[12, 7, 3]

True

Be aware that when using Alternatives you must manually order the patterns, for they are tried in sequence. The pattern args__ | {args__} would not work as desired because args__ will match {12, 7, 3} as a single argument.

$\endgroup$
8
$\begingroup$

There are many ways to handle this. The approach I would most likely take can be illustrated by the following example:

f[seqn : ___] := Module[{args = {seqn}},
    Switch[args,
       {{___}}, "List of args",
       {_}, "One arg",
       {_, __}, "Two or more args",
       {}, "No args"
    ]]

f[{x, y, z}]

(* ==> "List of args" *)

f[{x}]

(* ==> "List of args" *)

f[]

(* ==> "No args" *)

f[x]

(* ==> "One arg" *)

f[x, y, z]

(* ==> "Two or more args" *)

Of course, each application of this technique would replace the strings seen here with some action appropriate to its own needs.

Another approach is to write separate functions for each argument pattern you want to handle:

g[args : {___}] := "List of args"
g[] := "No args"
g[arg_] := "One arg"
g[arg_, rest__] := "Two or more args"

g[{x, y, z}]

(* ==> "List of args" *)

g[{x}]

(* ==> "List of args" *)

g[]

(* ==> "No args" *)

g[x]

(* ==> "One arg" *)

g[x, y, z]

(* ==> "Two or more args" *)
$\endgroup$
2
  • 5
    $\begingroup$ What is your reasoning for "most likely" using Switch over multiple definitions? Switch is usually slower and should not be used without cause, IMHO. $\endgroup$
    – Mr.Wizard
    Commented Dec 5, 2012 at 6:46
  • 1
    $\begingroup$ @Mr.Wizard. Using Switch appeals to my sense of programming aesthetics because it organizes all the alternatives so they can be dealt with in a single function. I'm usually not all that concerned about execution speed -- not until slow execution becomes really evident. $\endgroup$
    – m_goldberg
    Commented Dec 5, 2012 at 14:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.