Оцените за один уровень в Hold в Mathematica - PullRequest
8 голосов
/ 29 июня 2010

Документация 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]

В этом случае первое удержание сохраняет все недооцененным на первом уровне и за его пределами. Цель состоит в том, чтобы контролировать оценку выражения на каждом этапе от самой внутренней вложенной функции до внешней, используя для этого последовательные функции Hold, ReleaseHold и Evaluate. Я знаю, что мог бы использовать трассировку, чтобы увидеть, что происходит в выражении после первого уровня, но это отличается и иногда сложно для чтения с более длинными выражениями.

Кажется, что единственный способ - извлечь и полностью разобрать выражение в списки, используя Extract, Part или Level; оценить часть выражения, которое я хочу; затем восстановите и заново сопоставьте выражение для каждого этапа. Существуют ли другие подходы или функции для достижения этого, которые я мог бы рассмотреть?

Редактировать: Это может быть лучшим примером, чтобы взглянуть на подход освобождения первого удержания. С выражением:

Hold[Plus[Plus[2, Plus[2,2]], 2]]]

Если вы отпустите первую задержку и поместите удержание на более высокий уровень в выражении в третьем плюсе, чтобы выглядеть так:

in = Plus[Plus[2, Hold[Plus[2,2]]], 2]]]
out = Hold[2+2]+4

Вы обнаружите, что Mathematica будет оценивать более низкие уровни на заднем плане, когда вы действительно захотите его подождать.

Ответы [ 4 ]

3 голосов
/ 01 июля 2010

Как это часто бывает, когда вы хотите сделать что-то хитрое в 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; здесь вы ничего не делаете с локальной переменной, но форсируете ее оценку окольным путем - потому что менее окольные пути не будут работать!

ИЗМЕНИТЬ, чтобы добавить: Я думаю, что вы неправильно интерпретируете результат Level; два выражения на уровне {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 попытается сопоставить и заменить правило с этими двумя выражениями, и оно будет работать на втором.

3 голосов
/ 29 июня 2010

Я не могу дать точную причину, по которой 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}

НТН!

2 голосов
/ 24 января 2011

Используя идею о ReplacePart и Extract функциях из ответа от Михаила Пилата , можно написать HoldAndEvaluate функцию, которая позволяет ему оценить нужную частьвыражения без необходимости вычислять его положение (его можно пометить как «MyEvaluate»).

In[1]:= expr = Hold[MyEvaluate[2 + 2] + 2];

In[2]:= HoldAndEvaluate[expr_] :=
  ReplacePart[expr,
    # -> Evaluate @@ Extract[expr, #] & /@ 
    Position[expr, MyEvaluate[_]] ];

In[3]:= HoldAndEvaluate[expr]

Out[3]= Hold[4 + 2]
2 голосов
/ 29 июня 2010

Техника, которая не включает 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 s после того, как внутренности обернуты, так чтоНапример, плоскостность Plus пинает в:

DescentHold[2*3+(4+5)]
Out[4]= Hold[4]+Hold[5]+Hold[2*3]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...