1
$\begingroup$

Is it somehow possible to access and reference the sequence of arguments of a non-pure function?

For example if I want to take the derivative with respect to the n'th argument, a pseudocode example would be:

DiffNthArg[fun_,n_]:=D[fun,(*code for nth argument*)]

DiffNthArg[f[x,y,z],3]
Out[]: D[f[x,y,z],z]

I read that the one can extract the sequence of the function arguments by the following code: f /. f[z__]:>z Therefore one could use the following:

DiffNthArg[fun_,n_]:=D[fun, fun /. g_[z__] :> List[z][[n]] ]

BUT: This only works on undefined functions. If I apply it to already defined functions, the applied pattern will be applied to the already evaluated function, and thus does not return the list of function arguments.

For example, if I previously define f the following way, DiffNthArg will take the derivative with respect to c, not z:

f[x_,y_,z_]:= a b c z
DiffNthArg[f,3]
Out[]: a b z

How do I get the "original" argument sequence of the unevaluated function (even if it is already defined before)?

$\endgroup$
2
  • $\begingroup$ You probably want to add some form of Hold attribute to the definition of your function. It may be helpful to add a specific example. $\endgroup$
    – MarcoB
    Sep 1, 2021 at 17:07
  • $\begingroup$ I thought, I added two examples already (one how it should behave and one how it actually behaves). The problem is, that once defined, f will be substituted by its defined expression (a b c z) no matter which kind of Hold I wrap around it. $\endgroup$ Sep 1, 2021 at 18:24

1 Answer 1

2
$\begingroup$
g[a_,b_,c_]:= a b c + 2 a + 1

(* the [[1, 1]] gets the signature of f, 
   while the [[All, 1]] gets the symbol from the list of Pattern-s *)
argList[f_] := 
 ReleaseHold[DownValues[f][[1, 1]] /. {f -> List}][[All, 1]]

argList[g]
(** {a, b, c} **)

D[ g[a,b,c], argList[g][[3]] ]
(** a b **)
$\endgroup$
4
  • $\begingroup$ Brilliant, this works as intended! For some reason I thought there might be a more direct way of accessing function arguments which I just couldn't find in the documentation. But this way is just as fine as well. $\endgroup$ Sep 2, 2021 at 11:19
  • $\begingroup$ Ok, so there is one more question I have: Upon implementation, I realized that I could for example not do DFirst[f_] := D[f, argList[f][[1]]]. So if I define g[x,y]:=x+y, I would get DFirst[g[x,y]] --> 0. Why is that? Because argList needs as argument g but not g[x,y]. So when calling DFirst, instead of g being passed, x+y is passed to argList. Is there a way around that? $\endgroup$ Sep 3, 2021 at 19:09
  • $\begingroup$ @jabberwocky g[x,y] is the result of applying g to x,y, so what you're asking doesn't make much sense. You should do DFirst[g] instead. Also define g[x_, y_] := x + y not g[x,y]:=x+y - otherwise you'd need to change argList to argList[f_]:=ReleaseHold[DownValues[f][[1, 1]] /. f -> List] if not using patterns (x_, y_) $\endgroup$
    – flinty
    Sep 3, 2021 at 22:58
  • $\begingroup$ Ah I see, that makes sense. So writing DFirst[f_] := D[f[argList[f] /. List -> Sequence], argList[f][[1]]] will work as expected. Thanks for the clarification! $\endgroup$ Sep 4, 2021 at 14:14

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.