9

I was wondering if there were any important differences or stylistic considerations for deciding between different ways to define functions of multiple variables, e.g.

f[ x_, y_ ] := x + y
f[{x_, y_}] := x + y
f[x_][y_]   := x + y

Reviewing some of my code, I noticed that I do not follow any one pattern consistently. Does anyone have a principled approach?

MarcoB
  • 67,153
  • 18
  • 91
  • 189
Diffycue
  • 1,834
  • 8
  • 11
  • Each makes a certain usage more convenient or less convenient. For instance, do you want to take derivatives? Do you want f to have attributes like HoldAll or Listable? – Michael E2 Aug 17 '22 at 16:38
  • 3
    Using f[x][y] which is referred as subvalues of f is convenient when using Postfix notation like expression // f[x]. However, it is inconvenient when x has a default value like f[x_:0][y_]:=formula because if you do not want to specify a value for x you have to write expression // f[]. If instead you wrote f[y,x_:]:=formula then you could just write expression // f. – userrandrand Aug 17 '22 at 16:53
  • If the function treats all variables on a similar footing it can be convenient to use f[X_]:=formula where X is a list. This is true as well if you want to specify conditions for X like f[X_] /; VectorQ[X,NumericQ]:= formula – userrandrand Aug 17 '22 at 16:58
  • sorry in my first comment I should have wrote f[y,x_:0] instead of f[y,x_:] – userrandrand Aug 17 '22 at 16:59
  • 4
    f[{x_,y_}] can be handy for vector-valued functions, so Nest* can be applied – Chris K Aug 17 '22 at 17:09
  • 2
    An obvious advantage for f[{x_,y_}] is that if you are passing a small list (say a point with coordinates x,y,z). so Instead passing it as single variable say f[pt_List] and then having the function do pt[[1]] for x and pt[[2]] for y and so on, the function can just use the x,y,z names directly. The code becomes much more clear. – Nasser Aug 17 '22 at 17:39
  • 3
    Nest[Apply@f, {x, y},...] can be used on vector-valued outputs for f[x_, y_]. Likewise {x, y} // Apply@f. – Michael E2 Aug 17 '22 at 18:21
  • If f[x][y] evaluates to an algebraic expression, then D[f[x][y], x] works as expected. If g is undefined, then D[g[x][y], x] /. g -> f does not. – Michael E2 Aug 17 '22 at 18:23
  • 1
    It seems to me it will be hard to give an answer that addresses all issues. Well, maybe, "I use them all, too. Just use the one that works best in each situation." – Michael E2 Aug 17 '22 at 18:28
  • I sometimes use subvalues for functions of the form f[data][args], where data might be some state data, parameter values, method data, metadata, etc. Probably got this idea from exploring the NDSolve and NIntegrate caverns. – Michael E2 Aug 17 '22 at 20:04
  • 1
    Related: https://mathematica.stackexchange.com/questions/544/how-do-you-set-attributes-on-subvalues – Michael E2 Aug 17 '22 at 21:42
  • Maybe someone would like to compose an answer? It seems there is plenty of relevant stuff to mention that could be helpful to others. @MichaelE2 – Diffycue Aug 18 '22 at 23:40

1 Answers1

2

Not exactly answering your question, but if I wanted to define functions taking the arguments in these forms, I would make the definitions as minimal as possible. For example

f1[x__] := Plus[x]
f2[x_List] := Plus @@ x
f3[x_] := x + # &

{f1[3, 4], f2[{3, 4}], f3[3][4]} (* {7, 7, 7} *)

mikado
  • 16,741
  • 2
  • 20
  • 54