Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prohibit replacement by ReplaceAll (/.)

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?

like image 373
phantomas1234 Avatar asked Nov 14 '11 20:11

phantomas1234


2 Answers

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.

like image 159
Leonid Shifrin Avatar answered Nov 15 '22 05:11

Leonid Shifrin


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]
like image 21
Mr.Wizard Avatar answered Nov 15 '22 06:11

Mr.Wizard