Based on solutions proposed by @Leonid and @WReach I have noticed something peculiar with the use of Block
and With
for the Trott-Strzebonski
solution.
Consider the following code:
f[x_] := x^2;
g[x_] := x^3;
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = (g@*f)[n]},
Print[eval]; eval /; True
]
this will yield:
(*
64.
729.
Hold[{Hold[64.], Hold[729.]}]
*)
using Block
will give the same result as above.
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> Block[{eval = (g@*f)[n]},
Print@eval; eval /; True
]
(*
64.
729.
Hold[{Hold[64.], Hold[729.]}]
*)
However, things become strange - as @Leonid pointed out - with the use of Composite expression in Condition
:
using With
prevents the evaluation of Print
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = (g@*f)[n]},
(Print[eval]; eval) /; True
]
(* Hold[{Hold[Print[64.]; 64.], Hold[Print[729.]; 729.]}] *)
However, with the use of Block
the Print statements get evaluated
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> Block[{eval = (g@*f)[n]},
(Print@eval; eval) /; True
]
(*
64.
729.
Hold[{Hold[64.], Hold[729.]}]
*)
Now one begins to wonder how RuleCondition
- as mentioned by @WReach - will behave with Composite expression
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> RuleCondition[Print[(g@*f)[n]]; (g@*f)[n]]
(*
64.
729.
Hold[{Hold[64.], Hold[729.]}]
*)
It turns out that RuleCondition
behaves in a similar way to Block
So perhaps not a million dollar but a $5 question: Which one to use (Block, RuleCondition or With)?
In my opinion both have their own advantages. For instance, With
will allow you to evaluate a part of the expression and at the same time inject unevaluated code in the substitution process.
With
will enable code injection
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = (g@*f)[n]},
(g[eval]; eval) /; True
]
(* Hold[{Hold[g[64.]; 64.], Hold[g[729.]; 729.]}] *)
In the example above (in spirit with what @Leonid mentioned) we substituted the Reals
and also injected code that remained unevaluated i.e. g[64]
and g[729]
Block
and RuleCondition
together with Sow
and Reap
However, if the goal is to evaluate some code while making substitution 'Block` can be quite effective:
Reap[Hold[{Hold[2.], Hold[3.]}] /. n_Real :> Block[{eval = (g@*f)[n]},
(Sow[PrimeQ@eval]; eval) /; True
]][[2, 1]]
];
(* {False,False} *)
Reap[
Hold[{Hold[2.], Hold[3.]}] /. n_Real :> Block[{eval = (g@*f)[n]},
(Sow[EvenQ[Round@eval]]; eval) /; True]
]
(* {Hold[{Hold[64.], Hold[729.]}], {{True, False}}} *)
In the example above we could the result whether eval
generates a Prime whenever the substitution is made. Likewise, this can be achieved using RuleCondition
.