# 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)? – Michael Witt Nov 3 '15 at 5:43
• Why can't you define the general function first and the particular case later? test[t_]:= f[xx,yy,zz,t] – rhermans Nov 3 '15 at 7:33
• @MichaelWitt Oh, my god. I made a big mistake. I modified my post. I am so sorry – matheorem Nov 3 '15 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. – matheorem Nov 3 '15 at 8:06
• So, when you call f[xx,yy,zz,t] you want it to modify the value of argument? – Michael Witt Nov 3 '15 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
(* {{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}} *)