mathematica документация относительно Оценивает в возможных проблемах, говорит:
Оцените работы только на первом уровне, непосредственно в сохраненной функции
Почему Mathematica имеет это ограничение? Таким образом, если у меня есть выражение больше чем с одним уровнем, берут этот упрощенный пример:
Держите [Плюс [Плюс [2, 2], 2]]]
Теперь предположите, что я хочу видеть то, что ответ к второе Плюс, ничего не оценивая на уровнях ниже его. Я попробовал разные вещи, такие как:
In[290]:= Hold[Plus[Evaluate[Plus[2, 2]], 2]]
Out[290]= Hold[Evaluate[2+2]+2]
In[287]:= Hold[Plus[ReleaseHold[Hold[Plus[2, 2]]], 2]]
Out[287]= Hold[ReleaseHold[Hold[2+2]]+2]
Первое Хранение сохраняет все неоцененным в и вне первого уровня в этом случае. Цель состоит в том, чтобы управлять оценкой выражения на каждом этапе от самой внутренней вложенной функции до внешней с помощью последовательного Хранения, ReleaseHold и Оценить функции для достижения этого. Я знаю, что мог использовать трассировку для наблюдения то, что происходит вне уровня один в выражении, но это отличается и иногда сложно для чтения с более длительными выражениями.
Кажется, что единственный путь состоит в том, чтобы извлечь и полностью отменить выражение в списки с помощью Извлечения, Части или Уровня; оцените часть выражения, которое я хочу; затем восстановите и повторно отобразите выражение назад вместе для каждого этапа. Есть ли какие-либо другие подходы или функции для достижения этого, я мог рассмотреть?
Править: Это могло бы быть лучшим примером для рассмотрения подхода выпуска первого хранения. С выражением:
Hold[Plus[Plus[2, Plus[2,2]], 2]]]
Если Вы выпускаете первое хранение и помещаете хранение над более высоким уровнем в выражении в третьем Плюс, для сходства с этим:
in = Plus[Plus[2, Hold[Plus[2,2]]], 2]]]
out = Hold[2+2]+4
Вы находите, что Mathematica оценит более низкие уровни в фоновом режиме, когда Вы действительно захотите, чтобы он ожидал.
Я не могу назвать точную причину, почему Evaluate
«работает только на первом уровне, непосредственно внутри удерживаемой функции», но я подозреваю, что это частично эффективность, так как был бы медленным, если бы оценщику пришлось сканировать полное дерево выражений удерживаемых аргументов, переданных в любую функцию с атрибутом Hold *
для вложенных Вычислить
выражения и оценить их, а затем выполнить рекурсию и просмотреть for Оценивать подвыражения
в том, что они только что вычислили, при этом оставив остальную часть выражения невычисленной, особенно если это не всегда может быть тем, что вы хотите в любом случае.
Делать то, что вы хотите, довольно легко, используя комбинацию 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]
Это позволяет нам проиллюстрировать еще одну причину, по которой это может не иметь смысла для Оцените
для работы на любом уровне в выражении, переданном в качестве аргумента функции с атрибутом 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}
HTH !
Техника, которая не включает Extract
- это обернуть части внутри Hold
во внутренние Hold
ы, а затем отпустить внешний Hold
:
expr=Hold[(1+2)+3];
ReleaseHold@Map[Hold,expr,{2}]
Out[2]= Hold[3]+Hold[1+2]
Вы можете играть в различные игры в этом направлении, но поскольку я не могу сказать, что именно вы хотите сделать, немного трудно быть конкретным. Что-то, что может быть полезным, это определить свой собственный Hold
, который спускается так, как вы хотите:
SetAttributes[DescentHold,{HoldAll}]
DescentHold[a_Plus]:=ReleaseHold@Map[DescentHold,Hold[a],{2}]
DescentHold[a_]:=Hold[a]
Обратите внимание, что этот приближается к внешним Hold
ам после того, как внутренние обернуты, так что, например, плоскость Plus
начинает действовать:
DescentHold[2*3+(4+5)]
Out[4]= Hold[4]+Hold[5]+Hold[2*3]
Как это часто бывает, когда вы хотите сделать что-нибудь хитрое в системе Mathematica, на помощь приходят сопоставление с образцом и замена правил. Однако в этом случае вам нужно сделать что-то странное , и вы должны использовать Replace
вместо ReplaceAll
( /.
оператор), чтобы вы могли воспользоваться его необязательным третьим аргументом, чтобы задать ему уровень. Используя предложенный вами пример:
In[1]:= Replace[
Hold[Plus[Plus[2, 2], 2]],
expr_Plus :> With[{eval = expr}, eval /; True],
{2}]
Out[1]= Hold[4 + 2]
Бесполезное на вид
expr_Plus :> With[{eval = expr}, eval /; True]
правило на самом деле документированный способ совместного использования локальных переменных между тестовым соответствием и телом структуры With
; здесь вы ничего не делаете с локальной переменной, а заставляете ее вычислять окольными путями --- потому что менее окольные пути не работают!
ИЗМЕНИТЬ, чтобы добавить: Я думаю, вы неправильно интерпретируете результат Уровень
; два выражения на уровне {2}
этого выражения: 2
и Plus [2, 2]
; вы можете увидеть это, используя необязательный третий аргумент для уровня, который делает что-то похожее на необязательный третий аргумент Extract
:
In[2]:= Level[Hold[Plus[Plus[2, 2], 2]], {2}, Hold]
Out[2]= Hold[2 + 2, 2]
Со спецификацией уровня {2}
, Replace
попытается сопоставить и заменить правило для этих двух выражений и будет работать со вторым.