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$ Commented Feb 16, 2013 at 19:44
  • $\begingroup$ Yes, this is more concise. Thanks. $\endgroup$ Commented 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$ Commented 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$ Commented Feb 16, 2013 at 20:35
  • $\begingroup$ Yes, your additional answer together with PlatoManiac's answer makes this thread valueable for reading. $\endgroup$ Commented 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$ Commented Feb 16, 2013 at 20:46
  • $\begingroup$ @saturasl You are welcome. $\endgroup$ Commented 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$ Commented 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$ Commented 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$ Commented Feb 17, 2013 at 11:08

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.