When trying to simulate the evaluation behavior of RuleDelayed
I faced unexpected behavior of nested Unevaluated
. Consider:
In[1]:= f[Verbatim[Unevaluated][expr_]] := f[expr]
f[Unevaluated[1 + 1]]
f[Unevaluated@Unevaluated[1 + 1]]
f[Unevaluated@Unevaluated@Unevaluated[1 + 1]]
f[Unevaluated@Unevaluated@Unevaluated@Unevaluated[1 + 1]]
Out[2]= f[Unevaluated[1 + 1]]
Out[3]= f[2]
Out[4]= f[Unevaluated[1 + 1]]
Out[5]= f[2]
One can see that only even number of nested Unev开发者_高级运维aluated
wrappers are completely removed. Why?
The key is that, effectively, one layer of Unevaluated
is removed before the expression is pattern-matched. From the docs:
f[Unevaluated[expr]]
effectively works by temporarily setting attributes so thatf
holds its argument unevaluated, then evaluatingf[expr]
.
Thus, in the first case, f[Unevaluated[1 + 1]]
is evaluated as f[1 + 1]
, but remaining unevaluated during pattern matching even though f
lacks Hold*
attributes, and since nothing matches f[1 + 1]
, the original expression (pre-pattern-matching) is returned unevaluated.
In the second case, f[Unevaluated[Unevaluated[1 + 1]]]
evaluates as f[Unevaluated[1 + 1]]
in the pattern-matcher, which does match a pattern for f
, and then f[1 + 1]
is evaluated recursively, and thus you get f[2]
.
In the third case, f[Unevaluated[Unevaluated[Unevaluated[1 + 1]]]]
evaluates as f[Unevaluated[Unevaluated[Unevaluated[1 + 1]]]]
, matches, and recursively evaluates as f[Unevaluated[1 + 1]]
, and we're back to the first case.
In the fourth case, f[Unevaluated[Unevaluated[Unevaluated[Unevaluated[1 + 1]]]]]
matches on f[Unevaluated[Unevaluated[Unevaluated[1 + 1]]]]
, recursively evaluates f[Unevaluated[Unevaluated[1 + 1]]]
, and we're back to the second case.
HTH!
Use Trace to see why:
In[1]:= f[Verbatim[Unevaluated][expr_]]:=f[expr]
In[2]:= f[Unevaluated[1+1]]//Trace
Out[2]= {f[1+1],f[Unevaluated[1+1]]}
- Due to the defining special property of the
Unevaluated
language construct,f[Unevaluated[1 + 1]]
evaluates just likef[1 + 1]
except the1 + 1
is left unevaluated. f[1 + 1]
does not match the definition you gave forf
.- Therefore
f[Unevaluated[1 + 1]]
remains unevaluated.
Whereas:
In[3]:= f[Unevaluated@Unevaluated[1 + 1]] // Trace
Out[3]= {f[Unevaluated[1+1]],f[1+1],{1+1,2},f[2]}
- Due to the defining special property of the
Unevaluated
language construct,f[Unevaluated@Unevaluated[1 + 1]]
evaluates just likef[Unevaluated[1 + 1]]
except theUnevaluated[1 + 1]
is left unevaluated. f[Unevaluated[1 + 1]]
matches the definition you gave forf
, and evaluates tof[1 + 1]
.- Therefore
f[Unevaluated@Unevaluated[1 + 1]]
evaluates tof[2]
.
精彩评论