7
$\begingroup$

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!

$\endgroup$
2
  • 1
    $\begingroup$ How about Sequence @@ f[x, y, z]? $\endgroup$
    – Fabian
    Feb 16, 2013 at 19:44
  • $\begingroup$ Yes, this is more concise. Thanks. $\endgroup$
    – saturasl
    Feb 16, 2013 at 20:38

2 Answers 2

6
$\begingroup$

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.

$\endgroup$
3
  • $\begingroup$ Now there are two more ways to achieve the goal, Thanks! $\endgroup$
    – saturasl
    Feb 16, 2013 at 20:03
  • $\begingroup$ @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. $\endgroup$
    – Mr.Wizard
    Feb 16, 2013 at 20:35
  • $\begingroup$ Yes, your additional answer together with PlatoManiac's answer makes this thread valueable for reading. $\endgroup$
    – saturasl
    Feb 16, 2013 at 21:01
5
$\begingroup$

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
$\endgroup$
7
  • $\begingroup$ Your answer goes deep into the core language, and this is very valueable to me, thanks! $\endgroup$
    – saturasl
    Feb 16, 2013 at 20:46
  • $\begingroup$ @saturasl You are welcome. $\endgroup$ Feb 16, 2013 at 20:50
  • $\begingroup$ 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} $\endgroup$
    – Mr.Wizard
    Feb 17, 2013 at 0:16
  • $\begingroup$ @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. $\endgroup$ Feb 17, 2013 at 9:59
  • 1
    $\begingroup$ (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 $\endgroup$
    – Mr.Wizard
    Feb 17, 2013 at 11:08

Your Answer

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

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