From Mathematica's own documentation:
{g[1],Hold[g[1]]}/.g[n_]:>n+1
leads to
{2, Hold[1 + 1]}
My question: is there a way to protect subexpressions from being replaced by ReplaceAll? I am using composite constructs as variables, like
v[a, b]
and would like to be able to do stuff like this
v[a, b] + a - b /. {a -> x, b -> y}
leading to
v[a, b] + x - y
and not
v[x, y] + x - y
without complicated patterns. Unfortunately, using Replace and level specifications is not option.
This idiom
v[a, b] + a - b /. {catch_v -> catch, a -> x, b -> y}
works, as 'catch_v -> catch' prohibits the subsequent rules to be applied to v. But I would rather like to prohibit the replacement on the expression level (with some kind of Hold or HoldForm expression). Is this possible?
I am not aware of anything like this "out of the box", but one can achieve a similar effect by hiding the expressions where one does not want replacements, with some temporary symbols, then applying the rules, and then restoring those expressions back. Here is one way:
ClearAll[ReplaceProtect];
ReplaceProtect /: f_[ReplaceProtect[expr_, ptrn_], args___] :=
Module[{protectRules, ps, n = 0},
protectRules =
Cases[expr, x : ptrn :> (HoldPattern[x] -> ps[n++]), Infinity];
f[expr /. protectRules, args] /.
Replace[protectRules,
Verbatim[Rule][Verbatim[HoldPattern][x_], rhs_] :> (rhs :> x), {1}
]
]
Here is how one can use this:
In[42]:= ReplaceProtect[{g[1],Hold[g[1]]},_g]/.g[n_]:>n+1
Out[42]= {g[1],Hold[g[1]]}
In[43]:= ReplaceProtect[{g[1],Hold[g[1]]},_Hold]/.g[n_]:>n+1
Out[43]= {2,Hold[g[1]]}
In[44]:= ReplaceProtect[v[a,b]+a-b,_v]/.{a->x,b->y}
Out[44]= x-y+v[a,b]
I defined ReplaceProtect
with UpValues
in a rather general way, so it can be used also with Replace
and other functions which use rules.
Since ReplaceAll
is designed to "transform each subpart of an expression" and is often used specifically for the ability to operate inside of Hold
variations, you will need to use an inert form for your expression.
One method is to convert your expression into a string. Here is an example:
SetAttributes[holdAsString, HoldFirst]
holdAsString[expr : Except[_String]] :=
holdAsString @@ {ToString[Unevaluated@expr, InputForm]}
holdAsString[v[a, b]] + a - b /. {a -> x, b -> y} /. holdAsString -> ToExpression
x - y + v[a, b]
Another method is to use Compress
and Uncompress
. This may prove more robust.
SetAttributes[holdCompressed, HoldFirst]
holdCompressed[expr : Except[_String]] :=
holdCompressed @@ {Compress@Unevaluated@expr}
holdCompressed[v[a, b]] + a - b /. {a -> x, b -> y} /. holdCompressed -> Uncompress
x - y + v[a, b]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With