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.
ConditioninsideWithforces evaluation not onlyWith(with except to theCondition) but also enclosingModule? Without theConditionthe r.h.s of the rule stay completely unevaluated. – Alexey Popkov Jul 10 '11 at 04:03f[x_]:=Module[{var = x^2},With[{var = var},Hold[var]/;var>10]]. What happens is that everything in the enclosing scoping constructs that does not go intoConditiongets evaluated - this is needed to compute the result of test inCondition. The semantics of rules with shared local variables is different from the standard rule-substitution semantics, this is what makes all these things possible. The further non-triviality of Trott-Strzebonski technique is that local rules are used, so all expression levels are accessible. – Leonid Shifrin Jul 10 '11 at 07:45RuleCondition. – WReach Oct 06 '11 at 20:40RuleConditionhere before: http://stackoverflow.com/questions/5866016/question-on-condition/5869885#5869885, but it did not occur to me to try using it here. Nice finding! – Leonid Shifrin Oct 07 '11 at 08:23evalvariable to be evaluated inside the declaration part ofWith" e.g.Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = (Print["!"]; f[n])}, g[eval] /; False]will always print!even though the condition is False. – luyuwuli Aug 20 '20 at 16:13TrueorFalse, decides whether the rule is considered at the end as applicable or not, by the pattern matcher. I have edited the post to address this. Thanks for pointing this out. – Leonid Shifrin Aug 20 '20 at 21:48ResourceFunction["Inline"]is an implementation of the famous trick? If not, does it achieve the same objectives? – Gravifer Jun 07 '21 at 05:21