0
$\begingroup$

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.

$\endgroup$
1
  • $\begingroup$ Very closely related question (may be even a duplicate). $\endgroup$ May 7, 2014 at 11:36

1 Answer 1

2
$\begingroup$
x = {x1, x2, x3};

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

(* {1 + x1, 1 + x2, 1 + x3} *)
$\endgroup$
7
  • $\begingroup$ thanks! Can you explain why this works? $\endgroup$ May 7, 2014 at 4:59
  • $\begingroup$ @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! $\endgroup$
    – ciao
    May 7, 2014 at 5:09
  • $\begingroup$ Thanks, that clears it up. I had always been unclear on the difference between @ and @@. $\endgroup$ May 7, 2014 at 5:46
  • $\begingroup$ 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. $\endgroup$ May 7, 2014 at 11:47
  • 2
    $\begingroup$ @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. $\endgroup$ May 7, 2014 at 19:51

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.