Я не могу дать точную причину, по которой Evaluate
"работает только на первом уровне, непосредственно внутри удерживаемой функции", но я подозреваю, что это отчасти эффективность, в том смысле, что было бы медленно, если бы оценщик должен был сканировать полное дерево выражений содержащих аргументы, передаваемые любой функции с атрибутом Hold*
для вложенных выражений Evaluate
и их оценки, а затем рекурсивного поиска и поиска подвыражений Evaluate
в том, что он только что оценил, при этом остальная часть выражения остается без оценки особенно когда это может не всегда происходить так, как вы хотите.
Делать то, что вы хотите, довольно легко, используя комбинацию Extract
и ReplacePart
, хотя:
In[51]:= expr = Hold[Plus[Plus[2, 2], 2]];
In[52]:= ReleaseHoldAt[expr_, partspec_] :=
ReplacePart[expr, partspec -> Extract[expr, partspec]]
In[53]:= ReleaseHoldAt[expr, {1, 1}]
Out[53]= Hold[4 + 2]
Это позволяет нам проиллюстрировать еще одну причину, по которой Evaluate
может не иметь смысла работать на любом уровне в выражении, передаваемом в качестве аргумента функции с атрибутом Hold*
, учитывая следующее выражение, включающее i
:
In[82]:= i = 1;
In[83]:= ReleaseHoldAt[Hold[i = 2; j = Plus[i, i]], {1, 2}]
Out[83]= Hold[i = 2; 2]
Обратите внимание, что значение j
было бы 4
, если бы мы вычислили первую часть этого выражения до Plus
, но результаты отличаются, поскольку мы выполняем только частичную оценку, и i=2
не был оценен, когда мы оценивали настройку подвыражения j
. Иногда это может быть тем, что вы хотите, но часто это не так.
Имейте в виду, что даже Evaluate
на первом уровне можно победить с помощью функции с атрибутом HoldAllComplete
или с помощью HoldComplete
:
In[62]:= Hold[Evaluate[Plus[2,2]]]
Out[62]= Hold[4]
... в зависимости от:
In[63]:= HoldComplete[Evaluate[Plus[2,2]]]
Out[63]= HoldComplete[Evaluate[2+2]]
Наконец, вывод Trace
может быть немного плотным, но вы можете отфильтровать то, что вы хотите, используя шаблоны или символы, представляющие интерес во втором аргументе:
In[88]:= Trace[Plus[Plus[Plus[1,2],3],4],Plus]
Out[88]= {{{1+2,3},3+3,6},6+4,10}
In[93]:= Trace[Plus[Subtract[Plus[1,2],4],8],_Plus]
Out[93]= {{{1+2}},-1+8}
НТН!