为什么 RuleDelayed 不持有 Unevaluated? [英] Why doesn't RuleDelayed hold Unevaluated?

查看:23
本文介绍了为什么 RuleDelayed 不持有 Unevaluated?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Mathematica 的求值器通常持有(或恢复?)Heads Unevaluated 作为 Symbol<的参数提供的表达式/code>s:

In[1]:= f[s, Unevaluated[1 + 1]]Out[2]= f[s, 未评估[1 + 1]]In[5]:= Trace[f[s,Unevaluated[1+1]],TraceOriginal->True]Out[5]= {f[s,Unevaluated[1+1]],{f},{s},f[s,1+1],f[s,Unevaluated[1+1]]}

但对于 RuleDelayed 来说并非如此.此外,在 RuleDelayed 的情况下,任意Unevaluated 包装器被剥离:

In[1]:= Attributes@RuleDelayedRuleDelayed[s, Unevaluated[1 + 1]]RuleDelayed[s, Unevaluated@Unevaluated[1 + 1]]RuleDelayed[s, Unevaluated@Unevaluated@Unevaluated[1 + 1]]RuleDelayed[Unevaluated@Unevaluated@Unevaluated[1 + 1], 1 + 1]Out[1]= {HoldRest, Protected, SequenceHold}出[2]= s :>1 + 1出[3]= s :>1 + 1出[4]= s :>1 + 1出[5]= 2 :>1 + 1

RuleDelayed 的情况下,为什么评估器会删除 任意Unevaluated 包装器?它用于哪些目的?是否可以为任意 Symbol(例如,f)模拟这种行为?

<小时>

也不清楚为什么 TraceRuleDelayed 显示了比 f 更复杂的图片:

In[2]:= Trace[RuleDelayed[s,1+1],TraceOriginal->True]Out[2]= {s:>1+1,{RuleDelayed},{s},s:>1+1,s:>1+1,{RuleDelayed},{s},s:>1+1}

看起来 RuleDelayed 被评估了两次...

解决方案

Unevaluated 在作为规则中最外层的包装器出现时被剥离.这就是 Unevaluated 的工作原理,即 Unevaluated 不是一个评估任何东西的常规符号.它是一个令牌.比较

In[8]:= f[s_] := g[未评估[1 + 1]]In[9]:= DownValues[f]Out[9]= {HoldPattern[f[s_]] :>g[未评估[1 + 1]]}

In[10]:= f[s_] := Unevaluated[1 + 1]In[11]:= DownValues[f]Out[11]= {HoldPattern[f[s_]] :>1 + 1}

因为求值器是递归的,所以最终去掉Unevaluated就足够了.


EDIT 根据 Alexey 的评论扩展答案:

Unevaluated 是一个惰性符号,一个被求值者识别并在规则内执行的标记.为此,Unevaluated[1+1]f[1,Unevaluated[1+1]] 保持不变.当 RuleDelayed[s,Unevaluated[1+1]] 被求值时,Unevaluated 被剥离,然后整个 RuleDelayed 表达式在每次求值时重新求值原则.


EDIT 2 这是关于重新评估原因的讨论的浓缩结果

<块引用>`RuleDelayed` 的实现细节会导致重复评估,最终导致未评估的剥离.在我的答案下方的评论中,我提供了另一个命令的示例,该命令会出于完全相同的原因导致双重评估.发生这种情况是因为表达式经过验证,并且一旦验证,它就会被标记为某个有效标志.设置有效标志启动重新评估序列.这种情况一直发生,直到表达式不再改变.

其他需要验证的表达式也会出现类似的效果,例如 Root 对象:

In[41]:= Root[#1^6 + #1 - 1 &, 1];跟踪[Root[#1^6 + #1 - 1 &, 1],TraceOriginal ->真的]出[41]= {HoldForm[Root[#1^6 + #1 - 1 &, 1]], {HoldForm[Root]},{HoldForm[#1^6 + #1 - 1 &], {HoldForm[Function]},HoldForm[#1^6 + #1 - 1 &]},{保持形式[1]},HoldForm[Root[#1^6 + #1 - 1 &, 1]], <-- 这里的根是盖章有效,并重新评估HoldForm[Root[-1 + #1 + #1^6 &, 1]] <--评估是微不足道的.

}

The Mathematica's evaluator generally holds (or restores?) Heads Unevaluated of expressions supplied as arguments for Symbols:

In[1]:= f[s, Unevaluated[1 + 1]]

Out[2]= f[s, Unevaluated[1 + 1]]

In[5]:= Trace[f[s,Unevaluated[1+1]],TraceOriginal->True]

Out[5]= {f[s,Unevaluated[1+1]],{f},{s},f[s,1+1],f[s,Unevaluated[1+1]]}

But it is not true for RuleDelayed. Moreover, any number of Unevaluated wrappers are stripped in the case of RuleDelayed:

In[1]:= Attributes@RuleDelayed
RuleDelayed[s, Unevaluated[1 + 1]]
RuleDelayed[s, Unevaluated@Unevaluated[1 + 1]]
RuleDelayed[s, Unevaluated@Unevaluated@Unevaluated[1 + 1]]
RuleDelayed[Unevaluated@Unevaluated@Unevaluated[1 + 1], 1 + 1]

Out[1]= {HoldRest, Protected, SequenceHold}

Out[2]= s :> 1 + 1

Out[3]= s :> 1 + 1

Out[4]= s :> 1 + 1

Out[5]= 2 :> 1 + 1

Why does the evaluator strip any number of Unevaluated wrappers in the case of RuleDelayed? For which purposes is it useful? Is it possible to simulate such behavior for an arbitrary Symbol (f, for example)?


It is also not clear why the Trace shows more complicated picture for RuleDelayed than for f:

In[2]:= Trace[RuleDelayed[s,1+1],TraceOriginal->True]
Out[2]= {s:>1+1,{RuleDelayed},{s},s:>1+1,s:>1+1,{RuleDelayed},{s},s:>1+1}

It looks like RuleDelayed is evaluated twice...

解决方案

Unevaluated gets stripped when it occurs as the outermost wrapper in a rule. This is how Unevaluated works, i.e. Unevaluated is not a regular symbol which evaluates anything. It is a token. Compare

In[8]:= f[s_] := g[Unevaluated[1 + 1]]

In[9]:= DownValues[f]

Out[9]= {HoldPattern[f[s_]] :> g[Unevaluated[1 + 1]]}

And

In[10]:= f[s_] := Unevaluated[1 + 1]

In[11]:= DownValues[f]

Out[11]= {HoldPattern[f[s_]] :> 1 + 1}

Because evaluator is recursive, it suffices to get rid of Unevaluated eventually.


EDIT Expanding answer per Alexey's remark:

Unevaluated is an inert symbol, a token which is recognized by evaluator and acted upon within rules. For this reason Unevaluated[1+1] is unchanged, as well as f[1,Unevaluated[1+1]]. When RuleDelayed[s,Unevaluated[1+1]] is evaluated, Unevaluated is stripped, and then the entire RuleDelayed expression is reevaluated per evaluation principles.


EDIT 2 This is a condensed outcome of discussions on the cause for reevaluation

the implementation details of `RuleDelayed` cause repeated evaluations, which results in eventual stripping of the Unevaluated. In comments below my answer, I provided an example of another command which causes double evaluation for precisely the same reason. This happens because expression undergoes validation, and once validated, it is stamped with a certain valid flag. Setting the valid flag initiates reevaluation sequence. This is happening until expression no longer changes.

Similar effect occurs for other expression that require validation, like Root object:

In[41]:= Root[#1^6 + #1 - 1 & , 1]; Trace[Root[#1^6 + #1 - 1 & , 1], 
 TraceOriginal -> True]

Out[41]= {
 HoldForm[Root[#1^6 + #1 - 1 & , 1]], {HoldForm[Root]}, 
   {HoldForm[#1^6 + #1 - 1 & ], {HoldForm[Function]}, 
  HoldForm[#1^6 + #1 - 1 & ]}, 
   {HoldForm[1]}, 
  HoldForm[Root[#1^6 + #1 - 1 & , 1]],    <-- here the root had been 
                                              stamped valid, and reevaluated
   HoldForm[Root[-1 + #1 + #1^6 & , 1]]   <-- evaluation was trivial.

}

这篇关于为什么 RuleDelayed 不持有 Unevaluated?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆