Art Gower
Art Gower

Reputation: 213

Using Evaluate with a Pure Function and SetDelayed

I want to evaluate f below by passing a list to some function:

f = {z[1] z[2], z[2]^2};
a = % /. {z[1]-> #1,z[2]-> #2};
F[Z_] := Evaluate[a] & @@ Z ; 

So now if I try F[{1,2}] I get {2, 4} as expected. But looking closer ?F returns the definition

F[Z_] := (Evaluate[a] &) @@ Z

which depends on the value of a, so if we set a=3 and then evaluate F[{1,2}], we get 3. I know that adding the last & makes the Evaluate[a] hold, but what is an elegant work around? Essentially I need to force the evaluation of Evaluate[a], mainly to improve efficiency, as a is in fact quite complicated.

Can someone please help out, and take into consideration that f has to contain an Array[z,2] given by some unknown calculation. So writing

F[Z_] := {Z[[1]]Z[[2]],Z[[2]]^2}

would not be enough, I need this to be generated automatically from our f.

Many thanks for any contribution.

Upvotes: 2

Views: 370

Answers (1)

Mr.Wizard
Mr.Wizard

Reputation: 24336

Please consider asking your future questions at the dedicated StackExchange site for Mathematica.
Your questions will be much less likely to become tumbleweeds and may be viewed by many experts.


You can inject the value of a into the body of both Function and SetDelayed using With:

With[{body = a},
 F[Z_] := body & @@ Z
]

Check the definition:

Definition[F]
F[Z$_] := ({#1 #2, #2^2} &) @@ Z$

You'll notice Z has become Z$ due to automatic renaming within nested scoping constructs but the behavior is the same.


In the comments you said:

And again it bothers me that if the values of z[i] were changed, then this workaround would fail.

While this should not be a problem after F[Z_] is defined as above, if you wish to protect the replacement done for a you could use Formal Symbols instead of z. These are entered with e.g. Esc$zEsc for Formal z. Formal Symbols have the attribute Protected and exist specifically to avoid such conflicts as this.

This looks much better in a Notebook than it does here:

f = {\[FormalZ][1] \[FormalZ][2], \[FormalZ][2]^2};
a = f /. {\[FormalZ][1] -> #1, \[FormalZ][2] -> #2};

Another approach is to do the replacements inside a Hold expression, and protect the rules themselves from evaluation by using Unevaluated:

ClearAll[f, z, a, F, Z]

z[2] = "Fail!";

f = Hold[{z[1] z[2], z[2]^2}];
a = f /. Unevaluated[{z[1] -> #1, z[2] -> #2}] // ReleaseHold;

With[{body = a},
 F[Z_] := body & @@ Z
]

Definition[F]
F[Z$_] := ({#1 #2, #2^2} &) @@ Z$

Upvotes: 2

Related Questions