问题描述
Mathematica 的求值器通常持有(或恢复?)Head
s Unevaluated
作为 Symbols:
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
)模拟这种行为?
也不清楚为什么 Trace
为 RuleDelayed
显示了比 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?) Head
s Unevaluated
of expressions supplied as arguments for Symbol
s:
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
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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!