Ale*_*kov 7 wolfram-mathematica
的数学的评估器通常保持(或还原?)Head小号Unevaluated作为参数中提供的表达式的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]]}
Run Code Online (Sandbox Code Playgroud)
但事实并非如此RuleDelayed.此外,在以下情况下剥离任何数量的Unevaluated包装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
Run Code Online (Sandbox Code Playgroud)
为什么评估者会在任何Unevaluated情况下删除任意数量的包装器RuleDelayed?它的用途是什么?是否有可能为任意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}
Run Code Online (Sandbox Code Playgroud)
看起来像RuleDelayed被评估两次......
Unevaluated当它作为规则中最外层的包装器出现时被剥离.这是Unevaluated有效的方式,即Unevaluated不是评估任何东西的常规符号.这是一个象征.相比
In[8]:= f[s_] := g[Unevaluated[1 + 1]]
In[9]:= DownValues[f]
Out[9]= {HoldPattern[f[s_]] :> g[Unevaluated[1 + 1]]}
Run Code Online (Sandbox Code Playgroud)
和
In[10]:= f[s_] := Unevaluated[1 + 1]
In[11]:= DownValues[f]
Out[11]= {HoldPattern[f[s_]] :> 1 + 1}
Run Code Online (Sandbox Code Playgroud)
因为赋值器是递归的,所以Unevaluated最终摆脱它就足够了.
Unevaluated是一种惰性符号,一种由评估者识别并在规则内作用的代币.由于这个原因Unevaluated[1+1]没有改变,以及f[1,Unevaluated[1+1]].在RuleDelayed[s,Unevaluated[1+1]]评估时,将Unevaluated被剥离,然后RuleDelayed根据评估原则重新评估整个表达式.
`RuleDelayed`的实现细节导致重复评估,最终剥离Unevaluated.在我的回答下面的评论中,我提供了另一个命令的示例,该命令导致双重评估,原因完全相同.发生这种情况是因为表达式经过验证,一旦经过验证,就会标记一个有效的标志.设置有效标志会启动重新评估序列.这种情况一直发生,直到表达不再发生变化.
对于需要验证的其他表达式也会出现类似的效果,如Rootobject:
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.
Run Code Online (Sandbox Code Playgroud)
}
这个答案应被视为对@ Sasha答案的补充.我认为这是一个微妙的话题,可以从几个观点的解释中受益.
我想强调的是,所讨论的行为不是典型的,因为它不是大多数人在Mathematica中表现的方式,并且不能仅基于评估的一般原则(特别是Unevaluated剥离机制)来解释,没有诉诸具有此类行为的特定负责人的实施细节(RuleDelayed此处).考虑一些具有HoldRest属性的一般头部:
In[185]:= SetAttributes[h, HoldRest];
h[1, Unevaluated[Unevaluated[Unevaluated[1 + 1]]]]
Out[186]= h[1, Unevaluated[Unevaluated[Unevaluated[1 + 1]]]]
Run Code Online (Sandbox Code Playgroud)
而
In[209]:= 1:>Unevaluated@Unevaluated@Unevaluated[1+1]
Out[209]= 1:>1+1
Run Code Online (Sandbox Code Playgroud)
Unevaluated包装纸的一些细节这是基于David Wagner"Mathematica中的Power编程 - 内核"一书中的讨论,David Withoff的WRI技术报告,名为"Mathematica internals",以及我自己的经历.
这是一张非常简化的评估图.Mathematica递归地计算表达式,首先从"branches"(表达式)"向下"到"子分支"(子表达式)和离开(原子),然后"向上".在"向下"的路上,评估(子)表达式的头部,然后评估部分.具有头部的那些部分Unevaluated不会被进一步评估(在评估者没有被递归地调用它们的意义上),而Unevaluated被剥离并且标记为已经完成.在"向上"的路上,认为已经评估了部件.有许多的步骤,包括序列剪接,有关像属性的评价Flat,Orderless等.然后,对于其中评估是目前头的规则,应用,用户定义和内置(UpValues,DownValues,SubValues).最后,这对于本次讨论非常重要,Unevaluated对于那些没有找到适用规则的表达式部分,将恢复包装器.这就是为什么,对于未定义的函数f,我们有:
In[188]:= ClearAll[f];
f[Unevaluated[1+1]]
Out[189]= f[Unevaluated[1+1]]
Run Code Online (Sandbox Code Playgroud)
一个可以确认Unevaluated的包装被剥离,然后还原,通过使用Trace与TraceOriginal选项设置为True:
In[190]:= Trace[f[Unevaluated[1+1]],TraceOriginal->True]
Out[190]= {f[Unevaluated[1+1]],{f},f[1+1],f[Unevaluated[1+1]]}
Run Code Online (Sandbox Code Playgroud)
当为某些规则定义时会发生什么f?答案是每个规则应用程序剥离一层Unevaluated.这是一个例子:
In[204]:=
f[x_]:=Hold[x];
g[x_]:=f[x];
{f[Unevaluated[1+1]],g[Unevaluated[1+1]]}
{f[Unevaluated@Unevaluated[1+1]],g[Unevaluated@Unevaluated[1+1]]}
{f[Unevaluated@Unevaluated@Unevaluated[1+1]], g[Unevaluated@Unevaluated@Unevaluated[1+1]]}
Out[206]= {Hold[1+1],Hold[2]}
Out[207]= {Hold[Unevaluated[1+1]],Hold[1+1]}
Out[208]= {Hold[Unevaluated[Unevaluated[1+1]]],Hold[Unevaluated[1+1]]}
Run Code Online (Sandbox Code Playgroud)
如果一个人确切地知道表达式的特定部分将进行多少次评估,那么原则上可以将该部分包含在那么多层中Unevaluated以防止其评估.然而,这些信息通常不可能具有,并且Unevaluated不应该用作持久保持包装器 - 这Hold就是用途.但是,这种分析可能会更清楚地表明,为了使任何数量的评估失败,执行该评估的负责人必须具有为其定义的非平凡规则.换句话说,通常情况下,评估过程的一部分包括剥离一层Unevaluated不(本身,"在表达方式下"),诱导其重新评估 - 这可能只发生在"向上"的路上,由于为该头定义了一些规则.结论是观察到的行为RuleDelayed只能通过查看实现细节来解释RuleDelayed,一般考虑是不够的.
RuleDelayed我现在将说明这一点,并回答有关此行为模拟的原始问题的部分内容.据我所知,以下代码完全模拟了RuleDelayed剥离Unevaluated包装器的行为:
ClearAll[rd];
SetAttributes[rd, {HoldAllComplete, SequenceHold}];
rd[lhs_, Verbatim[Unevaluated][rhs_]] /;
Head[Unevaluated[rhs]] =!= Unevaluated := Append[rd[lhs], Unevaluated[rhs]];
rd[lhs_, Verbatim[Unevaluated][rhs_]] := rd @@ {lhs, rhs};
rd[lhs_, rhs_] /; Hold[lhs] =!= Hold[Evaluate[lhs]] := Prepend[rd[rhs], lhs];
Run Code Online (Sandbox Code Playgroud)
(对于其他人来说,它可能没有任何评估泄漏,但除此之外.我也无法做到HoldRest,就像RuleDelayed- 我不得不用HoldAllComplete这个结构来工作).你可以查看:
In[173]:=
a=1;
rd[a,Unevaluated[1+1]]
rd[a,Unevaluated@Unevaluated[1+1]]
rd[a,Unevaluated@Unevaluated[1+1]]
Out[174]= rd[1,1+1]
Out[175]= rd[1,1+1]
Out[176]= rd[1,1+1]
Run Code Online (Sandbox Code Playgroud)
这间接支持了我的论点,即可能是RuleDelayed实现,而不是评估者,对这种影响负责(尽管,我不能确定,我只能猜测.而且,这RuleDeleayed是非常基本的,这种异常行为可以连接到评估者)
编辑
为了进一步加强类比,以下是跟踪结果:
In[183]:=
DeleteCases[Trace[rd[s,Unevaluated[1+1]],TraceOriginal->True],
x_/;!FreeQ[x,Head|Hold|Append|HoldPattern[rd[_]]]]
Out[183]= {rd[s,Unevaluated[1+1]],{rd},rd[s,Unevaluated[1+1]],
rd[s,1+1],{rd},rd[s,1+1],rd[s,1+1]}
In[184]:= Trace[RuleDelayed[s,Unevaluated[1+1]],TraceOriginal->True]
Out[184]= {s:>Unevaluated[1+1],{RuleDelayed},{s},s:>1+1,s:>1+1,{RuleDelayed},{s},s:>1+1}
Run Code Online (Sandbox Code Playgroud)
跟踪结果非常相似.我曾经DeleteCases过滤掉中间评估rd.差异是由于HoldAllComplete属性rd对HoldRest的RuleDelayed.