Replacement inside held expression
Generally, you want the Trott-Strzebonski in-place evaluation technique:
f[x_Real]:=x^2;
Hold[{Hold[2.],Hold[3.]}]/.n_Real:>With[{eval = f[n]},eval/;True]
(* Hold[{Hold[4.],Hold[9.]}] *)
It will inject the evaluated r.h.s. into an arbitrarily deep location in the held expression, where the expression was found that matched the rule pattern. This is in contrast with Evaluate
, which is only effective on the first level inside Hold
(won't work in the example above). Note that you may evaluate some things and not evaluate others:
g[x_] := x^3;
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = f[n]}, g[eval] /; True]
(* Hold[{Hold[g[4.]], Hold[g[9.]]}] *)
The basic idea is to exploit the semantics of rules with local variables shared between the body of With
and the condition, but within the context of local rules. The eval
variable will be evaluated first (regardless of whether the condition ends up being True
- as in this case, or False
- thanks to @luyuwuli for pointing out the problem in the original wording for this part) , inside the declaration part of With
, while the code inside the Condition
, here the body of With
(g[eval]
), is treated then as normally the r.h.s. of RuleDelayed
is. It is important that With
is used, since it can inject into unevaluated expressions. Module
and Block
also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition
will remain unevaluated - see below). The body of With
above was not evaluated either, however With
injects the evaluated part ( eval
here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:
Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval=f[n]},
With[{eval = eval},g[eval]/;True]]
(* Hold[{Hold[g[4.]],Hold[g[9.]]}] *)
Note b.t.w. that only the part of code inside With
that is inside Condition
is considered a part of the "composite rule" and therefore not evaluated. So,
Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]},
With[{eval = eval},Print[eval];g[eval]/;True]]
(* print: 4. *)
(* print: 9. *)
(* Hold[{Hold[g[4.]],Hold[g[9.]]}] *)
But
Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]},
With[{eval = eval},(Print[eval];g[eval])/;True]]
(* Hold[{Hold[Print[4.];g[4.]],Hold[Print[9.];g[9.]]}] *)
This should further clarify this mechanism.
RuleCondition
provides an undocumented, but very convenient, way to make replacements in held expressions. For example, if we want to square the odd integers in a held list:
Hold[{1, 2, 3, 4, 5}] /. n_Integer :> RuleCondition[n^2, OddQ[n]]
(* Hold[{1, 2, 9, 4, 25}] *)
RuleCondition
differs from Condition
in that the replacement expression is evaluated before it is substituted. The second argument of RuleCondition
may be omitted, defaulting to True
:
Hold[{2., 3.}] /. n_Real :> RuleCondition[n^2]
(* Hold[{4., 9.}] *)
It is very unfortunate that RuleCondition
has remained undocumented for so long, given its extreme usefulness. The Trott-Strzebonski trick discussed in @Leonid's answer is one way to achieve the same result using only documented symbols:
Hold[{2., 3.}] /. n_Real :> With[{eval = n^2}, eval /; True]
(* Hold[{4., 9.}] *)
A slightly less verbose technique uses Block
:
Hold[{2., 3.}] /. n_Real :> Block[{}, n^2 /; True]
(* Hold[{4., 9.}] *)
Judicious use of Trace
reveals that both of these techniques ultimately resolve to RuleCondition
. One must make up one's mind whether it is better to use the undocumented RuleCondition
or rely upon implementation artifacts in With
and Block
. I suspect that the behaviour is unlikely to change in all three cases as so much Mathematica code depends upon the existing behaviour.
Although less magical, it can be done by ReplacePart
expr = Hold[{2, 3, 4, 5}]
pos = Position[expr, _Integer]
newparts = Extract[expr, pos] /. n_Integer :> n^2
ReplacePart[expr, Thread[pos -> newparts]]