# Method that can be used to collect the variables of a function

Suppose we have a function f[x, y, z] and we want to get all its variables Sequence[x,y,z], what method can we use then? The only one that I can come up with is like this:

f[x, y, z] /. func_[vars___] -> Sequence[vars]


But it is not very elegant from my point of view. Is there any more suitable method? Thanks!

-
How about Sequence @@ f[x, y, z]? –  Fabian Feb 16 '13 at 19:44
Yes, this is more concise. Thanks. –  saturasl Feb 16 '13 at 20:38

For one thing Sequence is applied automatically to a raw sequence (such as vars) if no other head is found, therefore:

f[x, y, z] /. _[vars___] :> vars

Sequence[x, y, z]


This is similar to what I have been calling the "injector pattern" and as you can see from that thread it has value in cases where Sequence @@ f[x, y, z] would not avail you, specifically inside symbols that will hold Sequence objects.

It is hard to guess your application from the question but you can also define a function, perhaps with additional conditions or handling of multiple forms of input, such as:

varSeq[expr_] :=
With[{vars = Variables @ expr}, Sequence @@ vars /; MatchQ[vars, {__Symbol}]]

varSeq[_@vars__Symbol] := vars


Now:

f[x, y, z] // varSeq

Sequence[x, y, z]

(x + y)^2 + 3 z^2 - y z + 7 // varSeq

Sequence[x, y, z]


Incidentally if you like terse coding you can also make use of SlotSequence, short form ##, as in:

## & @@ f[x, y, z]


which is equivalent to Sequence @@ f[x, y, z] in most cases.

-
Now there are two more ways to achieve the goal, Thanks! –  saturasl Feb 16 '13 at 20:03
@saturasl Thanks for the Accept. In the future consider waiting longer (I like 24 hours) to give everyone a chance to read the question and answer before it appears "concluded." Since you gave the Accept I added a couple of other things to my answer to try to cover other scenarios. –  Mr.Wizard Feb 16 '13 at 20:35

Probably irrelevant but I thought you have some function defined in the Global context and you want to get the list of its variables. If that is the case I came up with this messy solution.

Suppose you have defined a function like the following somewhere in a notebook and the definition for the symbol fun is available to the kernel as well as not Protected. I am defining the following example function using Module but one can also use Block.

Clear[f];
fun[x_, y_, z_] := Module[{val},
val = RandomReal[1, 3];
val . {x, y, z}
];


{x,y,z}

Then you can get the arguments of fun using the following

((DownValues[fun])[[1]] /.
RuleDelayed[HoldPattern[a___],b_] :> (Extract[a, 1, Hold] /. Hold[c_[vars___]] :> List@vars))


{x_, y_, z_}

If you want you can easily convert those pattern into Symbol using First /@%.

From the comments a more robust solution came out credit to Mr. Wizard.

Cases[ DownValues[fun], HoldPattern[fun][vars__] :> {vars}, -1 ] /.
Verbatim[Pattern][name_, _] :> name

-
Your answer goes deep into the core language, and this is very valueable to me, thanks! –  saturasl Feb 16 '13 at 20:46
@saturasl You are welcome. –  PlatoManiac Feb 16 '13 at 20:50
Your method as written is not robust in all cases, for example f[x_, y_, z_] /; something := . . .; it also doesn't address multiple definitions. For the simple case it is shorter to write: DownValues[fun][[1, 1]] /. _@_@vars___ :> {vars} –  Mr.Wizard Feb 17 '13 at 0:16
@Mr.Wizard you are right! I was sure my solution will not be general. But do think it is possible to have a solution that works for all type of function definition? it will be good to know. –  PlatoManiac Feb 17 '13 at 9:59
(1) I didn't mean to disparage your answer; only to let new users know that it has limitations. (2) I expect there would still be corner cases that would slip through the cracks but something fairly general should be possible; here's a first attempt: Cases[ DownValues[fun], HoldPattern[fun][vars__] :> {vars}, -1 ] /. Verbatim[Pattern][name_, _] :> name` –  Mr.Wizard Feb 17 '13 at 11:08