# How to properly define this function of function

I encountered real problem at first, and here is the toy example

variable argument stored some expression that is generated from other parts of the program. I suppose it's content is {xx, yy, zz}

argument = {xx, yy, zz}


and define a function test

test[argument_,t_] := {argument^2, Range[t]}


test function has only t as variable. Because when I use test, I don't need to substitute values into xx,yy,zz, I just manipulate expression stored in argument.

Now I want to define another function that has full control of xx,yy,zz,tin test function in order to get numerical results.

So I tried

f[xx_,yy_,xx_, t_] := test[t]


This won't work, because test[t] is hold. f[1,1,1,1] will give

{{xx^2, yy^2, zz^2}, {1}}


and this won't work either

f[xx_,yy_,xx_, t_] := Evaluate@test[t]


Though Evaluate unhold argument, while Range[t] can't be evaluated with letter t at the first step. So it will give errors like

Range::range: Range specification in Range[t] does not have appropriate bounds. >>

So how to do it?

ps:

For this simple case, surely I could directly define in this way.

f[xx_, yy_, zz_, t_] := test[{xx, yy, zz}, t];


But this is not what I want. As I said, the argument is dynamically generated by other parts of the program, so we cannot use its explicit form.

• I don't think it's entirely clear what you want to do. Also, did you mean to have separate variables kx and xx (and the same for yy and zz)? Commented Nov 3, 2015 at 5:43
• Why can't you define the general function first and the particular case later? test[t_]:= f[xx,yy,zz,t] Commented Nov 3, 2015 at 7:33
• @MichaelWitt Oh, my god. I made a big mistake. I modified my post. I am so sorry Commented Nov 3, 2015 at 8:05
• @rhermans That is because argument is dynamically generated by other part of the program in my real case, not like {xx,yy,zz} this simple. Commented Nov 3, 2015 at 8:06
• So, when you call f[xx,yy,zz,t] you want it to modify the value of argument? Commented Nov 3, 2015 at 8:13

You can use Block inside body of f function to temporarily set desired symbols to those passed as arguments of f.

ClearAll[argument, f, test]
argument = {xx, yy, zz};
test[t_] := {argument^2, Range[t]}
f[kx_, ky_, kz_, t_] := Block[{xx = kx, yy = ky, zz = kz}, test[t]]

f[a, b, c, 4]
(* {{a^2, b^2, c^2}, {1, 2, 3, 4}} *)


Alternatively you could first define general function f and then its specialized version test as suggested by @rhermans.

We start with argument[...] function instead of argument variable:

ClearAll[argument, f, test]

Block[{xx, yy, zz},
argument[xx_, yy_, zz_] := Evaluate[
Print["Time consuming calculation of argument."];
{xx, yy, zz}
]
]
(* Time consuming calculation of argument. *)


Now argument[...] gives you precalculated expression with proper values of xx, yy, zz inserted.

argument[a, b, c]
(* {a, b, c} *)


Now we can define f and then test:

f[xyz:PatternSequence[xx_, yy_, zz_], t_] := {argument[xyz]^2, Range[t]}
test[t_] := f[xx, yy, zz, t]

test[5]
(* {{xx^2, yy^2, zz^2}, {1, 2, 3, 4, 5}} *)
f[a, b, c, 10]
(* {{a^2, b^2, c^2}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}} *)