0

Previously, I've defined a function with a variable number of arguments with the following method.

x = {x1, x2, x3};
f1 = Function[
  Evaluate[x],
  x + 1 //
  Evaluate
];
f1 @@ x
Output: {1 + x1, 1 + x2, 1 + x3}

Also, I've defined a function that returned a function as follows.

g[x_] := Function[
  {z},
  x + z //
  Evaluate
];
f2 = g @@ {z};
f2 @@ {x1}
Output: x1 + z

But when I attempt to put these ideas together, I have an issue. The hang-up seems to be in passing the argument of the first function to the argument of the second. Note that in our second example, above, we weren't passing x as an argument to the inner function. However, this is exactly what we want to do:

h[x_] := Function[
  Evaluate[x],
  x + 1 //
  Evaluate
];
f3 = h @@ x;
f3 @@ x
Output: h[x1, x2, x3][x1, x2, x3]

The desired output is {1 + x1, 1 + x2, 1 + x3}. My motivation for writing such a function is to bury it in a package.

Rico Picone
  • 885
  • 1
  • 5
  • 12

1 Answers1

2
x = {x1, x2, x3};

h[x_] := Function[Evaluate[x], x + 1 // Evaluate];
f3 = h@x
f3 @@ x

(* {1 + x1, 1 + x2, 1 + x3} *)
ciao
  • 25,774
  • 2
  • 58
  • 139
  • thanks! Can you explain why this works? – Rico Picone May 07 '14 at 04:59
  • @RicoPicone: When you Apply (@@), think of it as basically turning your list into the arguments to the function. So in your example, you're trying to apply a function of one argument to three, so since it doesn't match, it returns unevaluated. In your next step, you're applying that to the list, giving you the h[x1, x2, x3][x1, x2, x3] nonsense. By changing your first operation to just @ (function invocation), the whole list is passed as the argument, allowing a function of three arguments to be returned, so the following Apply matches it, presto. If not clear, comment! – ciao May 07 '14 at 05:09
  • Thanks, that clears it up. I had always been unclear on the difference between @ and @@. – Rico Picone May 07 '14 at 05:46
  • The problem with this solution is that it will leak evaluation in cases where x1, etc. have prior values. But the real problem is how the question is formulated, because it is rather hard to partially evaluate the input to a list of symbols but not further. Put another way, what is asked for is a macro rather than a function, but Mathematica has no read-time, and so writing this sort of macros is hard, since macro-expansion gets mixed with evaluation. – Leonid Shifrin May 07 '14 at 11:47
  • @LeonidShifrin, that's a good point. This was my way of trying to write something that generates a function with a variable number of arguments. Is there a better workaround? – Rico Picone May 07 '14 at 19:20
  • 2
    @RicoPicone The biggest problem is that you store a list of variables in another variable. If you'd be fine with always supplying it explicitly, then the following modification of Rasher's solution would do: SetAttributes[h, HoldAll]; h[vars:{___Symbol}]:=Block[vars, Block[vars, Function @@ {vars, vars + 1}]]. If you want to store your variable list somewhere, the best thing to do is to store them in some HoldAll / HoldAllComplete-attributes-carrying container (e.g. Hold[]), and then redefine h to work as h[Hold[sym___Symbol]]:=.... Otherwise, it gets harder. – Leonid Shifrin May 07 '14 at 19:51
  • @LeonidShifrin, thanks, I like that advice. In my application it is convenient to define a list and make the entries of the list the arguments (and not the list itself) of a function because I will later differentiate that function with respect to its arguments. (I'm generating systems of pdes from these functions.) I like to write my routines to work for the n-variable case, which precludes explicitly specifying the inputs. If I can think of a simple way to explain my application and the nuances that arise, I'll try to ask it as a question. – Rico Picone May 08 '14 at 22:35