Why doesn't it work?
Evaluate
only has effect at the first level in a held expression.
{Hold[1 + 1], Hold[Evaluate[1 + 1]], Hold[f[1 + 1]]}
(* {Hold[1 + 1], Hold[2], Hold[f[1 + 1]]} *)
Why does Evaluate
only work at the first level?
Because the evaluator does not look for exceptions beyond the first level inside an expression having a head with HoldAll
. If it did, it may potentially spend a lot of time scanning large expressions.
Read about evaluation:
What's the solution?
Typically one has to use Replace
or ReplaceAll
.
Function[x, y] /. y -> x^2
(* Function[x, x^2] *)
All this falls under the label of code-generation, a difficult topic where things may go wrong all too easily due to how Mathematica implements scoping using variable renaming.
Example of how things may go wrong:
Can't we just use With
instead of Replace
? Let's try:
With[{y = x^2}, Function[x, y]]
(* Function[x$, x^2] *)
Oops! The function argument got renamed from x
to x$
to prevent a name collision. At the same time it "broke" our function. This is the reason why Replace
and ReplaceAll
are better than With
for such purposes.
But is Replace
bulletproof? Not at all, unfortunately. When doing such a transformation, we might want to localize y
. Let's see what happens.
Module[{y},
Function[x, y] /. y -> x^2
]
(* Function[x$, x^2] *)
Oops! The renaming kicked in again. (Note: Block
won't rename here but it's not always a good replacement to Module
.)
Doing such things can also lead to situations where SetSystemOptions["StrictLexicalScoping" -> True]
may make a significant difference (may fix or break things). This is why Stan Wagon's FindRoots2D function won't work (as posted on this site) if strict lexical scoping is turned on.
Sometimes we can use a trick like this to avoid variable renaming:
Module[{y}, Function @@ Hold[x, y] /. y -> x^2]
(* Function[x, x^2] *)
Writing Function @@ Hold[...]
instead of Function[...]
prevents the renaming (for better or worse).
To sum up, code generation seems to be quite difficult in Mathematica. Caution is advised. Now if someone could prove me wrong, I would be very happy ... Looking forward to other answers!
With
$\endgroup$Replace
is better, but can also end up with surprising results, see my answer. I don't have a good solution! :'( $\endgroup$