Wolfram mathematica 在“规则”列表中使用“With”-但不影响“With”的正常行为`

Wolfram mathematica 在“规则”列表中使用“With”-但不影响“With”的正常行为`,wolfram-mathematica,Wolfram Mathematica,假设我有一个规则列表 rules = {a -> b, c -> d}; 我在整个笔记本中都使用它。然后,在某一点上,希望在表达式中进行任何其他求值之前应用规则是有意义的。通常,如果你想要这样的东西,你会使用 In[2]:= With[{a=b,c=d}, expr[a,b,c,d]] Out[2]= expr[b, b, d, d] 如何获取规则并将其插入With的第一个参数中 编辑 这两种解决方案都无法实现我所期望的目标,但我本应进一步强调这一点。见上面粗体部分 例如,让我

假设我有一个
规则列表

rules = {a -> b, c -> d};
我在整个笔记本中都使用它。然后,在某一点上,希望在表达式中进行任何其他求值之前应用规则是有意义的。通常,如果你想要这样的东西,你会使用

In[2]:= With[{a=b,c=d}, expr[a,b,c,d]]
Out[2]= expr[b, b, d, d]
如何获取
规则
并将其插入
With
的第一个参数中


编辑 这两种解决方案都无法实现我所期望的目标,但我本应进一步强调这一点。见上面粗体部分

例如,让我们看看

rules = {a -> {1, 2}, c -> 1};
如果将
中的这些值与
一起使用,则

In[10]:= With[{a={1,2},c=1}, Head/@{a,c}]
Out[10]= {List,Integer}
带有规则的
的某些版本产生

In[11]:= WithRules[rules, Head/@{a,c}]
Out[11]= {Symbol, Symbol}
事实上,我没有注意到Andrew的答案具有属性
HoldRest
,因此它的工作原理与我所希望的一样。)

您想使用它来构建With语句。这是一种方法;可能有更简单的方法:

In[1]:= SetAttributes[WithRules, HoldRest]

In[2]:= WithRules[rules_, expr_] := 
 With @@ Append[Apply[Set, Hold@rules, {2}], Unevaluated[expr]]
测试一下:

In[3]:= f[args___] := Print[{args}]

In[4]:= rules = {a -> b, c -> d};

In[5]:= WithRules[rules, f[a, c]]

During evaluation of In[5]:= {b,d}

(我使用了Print,因此任何涉及我过早地意外评估expr的错误都会变得明显。)

我使用以下形式的
with rules
已经很长时间了。与Andrew Moylan发布的版本相比,它是按顺序绑定的,因此您可以使用规则[{a->b+1,b->2},expr]
,并将
a
扩展到
3

SetAttributes[WithRules, HoldRest]
WithRules[rules_, expr_] := ReleaseHold@Module[{notSet}, Quiet[
     With[{args = Reverse[rules /. Rule[a_, b_] -> notSet[a, b]]},
       Fold[With[{#2}, #1] &, Hold@expr, args]] /. notSet -> Set, 
   With::lvw]]
这也是作为一个发布的,正如上面提到的,它已经(至少)在usenet上讨论过几次:


编辑:添加了一个
ReleaseHold
Hold
对,以使
expr
在应用规则之前保持未计算状态。

Andrew解决方案的一个问题是,它将问题映射回with,并且不接受下标变量。因此,下面生成消息

WithRules[{Subscript[x, 1] -> 2, Subscript[x, 2] -> 3}, 
 Power[Subscript[x, 1], Subscript[x, 2]]]
鉴于
With
在其主体上执行语法替换,我们可以按如下方式交替设置规则:

ClearAll[WithRules]; SetAttributes[WithRules, HoldRest];
WithRules[r : {(_Rule | _RuleDelayed) ..}, body_] := 
 ReleaseHold[Hold[body] /. r]
然后

编辑:针对Leonid提出的合理担忧,以下版本是安全的:

ClearAll[WithRules3]; SetAttributes[WithRules3, HoldRest];
WithRules3[r : {(_Rule | _RuleDelayed) ..}, body_] := 
 Developer`ReplaceAllUnheld[Unevaluated[body], r]
然后

编辑2:即使使用规则3也不能完全等同于Andrew的版本:

In[206]:= WithRules3[{z -> 2}, f[y_] :> Function[x, x + y + z]]

Out[206]= f[y_] :> Function[x, x + y + z]

In[207]:= WithRules[{z -> 2}, f[y_] :> Function[x, x + y + z]]

Out[207]= f[y$_] :> Function[x$, x$ + y$ + 2]

谢谢Janus!既然你提到了它,我至少记得其中一个“顺序
”。你的答案与我想要的不太一样-请看编辑。@Simon,将其修改为实际答案:)如果这是所需的全部内容,就不能只做
Unevaluated[Subscript[x,1]^Subscript[x,2]/。{Subscript[x,1]->2,Subscript[x,2]->3}
?@Mr.Wizard是的,这是另一种选择。With和基于规则的替换在语义上存在细微的差异,当“body”中的代码具有嵌套的作用域结构,局部变量名与规则中的某些符号冲突时,就会出现这种差异。使用With将有利于内部构造,使用规则将有利于外部规则,并破坏内部作用域构造绑定。什么是有利的,取决于所讨论的代码,但我的感觉是“With”方式通常更安全。不错。拥有一个处理非符号(如下标变量)的With版本是一个非常方便的概括。@Andrew,正如我已经评论过的,这实际上不是一个带有
版本,而是一个将外部规则应用程序自动化到未赋值表达式的实用程序。例如,尝试使用规则[{x->y},f[y\u]:>Function[x,x+y]]
和您和@Sasha的解决方案,以查看差异。在词汇范围内,我认为规则替代更危险。尤其是Mathematica中函数抽象(
函数
)中的漏洞,上面的代码片段演示了其中一个。
In[194]:= WithRules3[{Subscript[x, 1] -> 2, Subscript[x, 2] -> 3}, 
 Subscript[x, 1]^Subscript[x, 2]]

Out[194]= 8

In[195]:= WithRules3[{x -> y}, f[y_] :> Function[x, x + y]]

Out[195]= f[y_] :> Function[x, x + y]
In[206]:= WithRules3[{z -> 2}, f[y_] :> Function[x, x + y + z]]

Out[206]= f[y_] :> Function[x, x + y + z]

In[207]:= WithRules[{z -> 2}, f[y_] :> Function[x, x + y + z]]

Out[207]= f[y$_] :> Function[x$, x$ + y$ + 2]