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?


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.

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

(* {{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}} *)
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.