来自Mathematica自己的文档:
{g[1],Hold[g[1]]}/.g[n_]:>n+1
导致
{2, Hold[1 + 1]}
我的问题:有没有办法保护子表达式不被ReplaceAll取代?我使用复合构造作为变量,如
v[a, b]
并希望能够做到这样的事情
v[a, b] + a - b /. {a -> x, b -> y}
导致
v[a, b] + x - y
而不是
v[x, y] + x - y
没有复杂的模式。不幸的是,使用替换和级别规范不是选项。
这个成语
v[a, b] + a - b /. {catch_v -> catch, a -> x, b -> y}
作为'catch_v - >工作catch'禁止后续规则应用于v。但我宁愿禁止在表达层面上替换(使用某种Hold或HoldForm表达式)。这可能吗?
答案 0 :(得分:5)
我不知道这样的“开箱即用”,但是可以通过隐藏不需要替换的表达式,使用一些临时符号,然后应用规则,然后恢复那些来实现类似的效果回归表达。这是一种方式:
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}
]
]
以下是如何使用它:
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]
我使用ReplaceProtect
以相当一般的方式定义UpValues
,因此它也可以与Replace
和其他使用规则的函数一起使用。
答案 1 :(得分:5)
由于ReplaceAll
旨在“转换表达式的每个子部分”,并且通常专门用于在Hold
变体内部操作的能力,因此您需要为表达式使用惰性表单
一种方法是将表达式转换为字符串。这是一个例子:
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]
另一种方法是使用Compress
和Uncompress
。这可能会更加强大。
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]