在 Mathematica 中的 Hold 中评估超过一级

发布于 2024-09-07 00:55:56 字数 1040 浏览 2 评论 0原文

关于 Evaluate at possible issues 的 mathematica 文档说:

仅评估第一个作品 级别,直接在持有的函数内

为什么 Mathematica 有这个限制?因此,如果我有一个以上级别的表达式,请采用以下简化示例:

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

现在假设我想看看第二个 Plus 的答案是什么,而不评估任何内容在低于它的水平上。我尝试过不同的事情,例如:

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]]]

如果您释放第一个保留并在第三个 Plus 处的表达式中将保留置于较高级别上,则如下所示:

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

您会发现,当您确实希望 Mathematica 等待时,它会在后台计算较低级别。

The mathematica documentation on Evaluate at possible issues says:

Evaluate works only on the first
level, directly inside a held function

Why does Mathematica have this limitation? So if I have an expression with more than one level take this simplified example:

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

Now suppose I want to see what the answer is to the the second Plus, without evaluating anything on levels below it. I've tried different things such as:

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]

The first Hold keeps everything unevaluated at and beyond the first level in this case.
The goal is to control evaluation of an expression at each stage from the most inner nested function to the outer one using successive Hold, ReleaseHold and Evaluate functions to achieve that. I know I could use trace to see what happens beyond level one in an expression but that is different and sometimes complex to read with longer expressions.

It seems like the only way is to extract and totally dismantle the expression into lists using Extract, Part or Level; evaluate part of the expression that I want; then reconstruct and re-map the expression back together for each stage. Are there any other approaches or functions for achieving this I could consider?

Edit: This might be a better example to look at the approach of releasing the first hold. With the expression:

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

If you release the first hold and place a hold on a higher level in a expression at the third Plus, to look like this:

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

You find that Mathematica will evaluate lower levels in the background when you really want it to wait.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烟织青萝梦 2024-09-14 00:55:56

我无法给出 Evaluate “仅在第一级工作,直接在保留函数内工作”的确切原因,但我怀疑这部分是效率问题,因为如果评估器必须扫描,它会很慢传递给具有嵌套 Evaluate 表达式的 Hold* 属性的任何函数的完整表达式树,并对它们进行求值,然后递归并查找 Evaluate 子表达式在它刚刚计算的内容中,同时保持表达式的其余部分不计算,特别是当这可能并不总是您想要发生的情况时。

不过,使用 ExtractReplacePart 的组合来完成您想要的操作非常容易:

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]

请注意 的值如果我们在 Plus 之前计算该表达式的第一部分,>j 将会是 4,但结果会有所不同,因为我们只进行部分计算,并且当我们计算子表达式设置 j 时,尚未计算 i=2。有时,这可能是您希望发生的事情,但通常情况下它很可能不是。

请记住,即使第一级中的 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!

I can't give the exact reason why Evaluate "works only on the first level, directly inside a held function" but I suspect it's partly efficiency, in that it would be slow if the evaluator had to scan the complete expression tree of held arguments passed to any function with a Hold* attribute for nested Evaluate expressions and evaluate them, and then recurse and look for Evaluate subexpressions in what it just evaluated, all while keeping the rest of the expression unevaluated, especially when this might not always be what you want to happen anyway.

Doing what you want is pretty easy using a combination of Extract and ReplacePart though:

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]

This lets us illustrate another reason why it might not make sense for Evaluate to work at any level in an expression passed as an argument to a function with a Hold* attribute, considering the following expression involving i:

In[82]:= i = 1;

In[83]:= ReleaseHoldAt[Hold[i = 2; j = Plus[i, i]], {1, 2}]

Out[83]= Hold[i = 2; 2]

Note that the value of j would have been 4 if we had evaluated the first part of that expression before the Plus, but the results are different since we are only doing partial evaluation, and i=2 had not been evaluated when we evaluated the subexpression setting j. Sometimes, this may be what you want to happen, but often it is very likely not.

Keep in mind that even Evaluate in the first level can be defeated by a function that has the attribute HoldAllComplete or by using HoldComplete:

In[62]:= Hold[Evaluate[Plus[2,2]]]
Out[62]= Hold[4]

...versus:

In[63]:= HoldComplete[Evaluate[Plus[2,2]]]
Out[63]= HoldComplete[Evaluate[2+2]]

Finally, the output of Trace can be a little dense, but you can filter out what you want by using patterns or symbols of interest in the second argument:

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!

满地尘埃落定 2024-09-14 00:55:56

当您想在 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} 级别的两个表达式是 2Plus[2, 2];您可以通过使用 level 的可选第三个参数来看到这一点,它的作用类似于 Extract 的可选第三个参数:

In[2]:= Level[Hold[Plus[Plus[2, 2], 2]], {2}, Hold]
Out[2]= Hold[2 + 2, 2]

使用 {2} 级别规范,Replace 将尝试根据这两个表达式匹配并替换规则,并且它将对第二个表达式起作用。

As is so often the case when you want to do something tricky in Mathematica, pattern matching and rule replacement come to the rescue. However, in this instance, you have to do something weird, and you have to use Replace instead of ReplaceAll (the /. operator) so you can take advantage of its optional third argument to give it a level specification. Using the example you offered:

In[1]:= Replace[
         Hold[Plus[Plus[2, 2], 2]],
         expr_Plus :> With[{eval = expr}, eval /; True],
         {2}]
Out[1]= Hold[4 + 2]

The useless-looking

expr_Plus :> With[{eval = expr}, eval /; True]

rule is actually a documented way to share local variables between the test match and the body of the With structre; here you don't do anything with the local variable but force its evaluation in a roundabout way---because less roundabout ways won't work!

EDIT to add: I think you're mis-interpreting the result of Level; the two expressions at level {2} of this expression are 2 and Plus[2, 2]; you can see this by using the optional third argument to level, which does something similar to the optional third argument of Extract:

In[2]:= Level[Hold[Plus[Plus[2, 2], 2]], {2}, Hold]
Out[2]= Hold[2 + 2, 2]

With the {2} level spec, Replace will try to match-and-replace the rule against these two expressions, and it will work on the second one.

硬不硬你别怂 2024-09-14 00:55:56

不涉及 Extract 的技术是将 Hold 内的部分包装在内部 Hold 中,然后释放外部 Hold< /code>:

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]

A technique which does not involve Extractis to wrap the parts inside Hold in inner Holds, and then release the outer Hold:

expr=Hold[(1+2)+3];
ReleaseHold@Map[Hold,expr,{2}]

Out[2]= Hold[3]+Hold[1+2]

You can play various games in this direction, but since I can't tell what it is you want to do, it is a bit hard to be specific. Something that might be useful is to define your own Hold that descents however you want it to:

SetAttributes[DescentHold,{HoldAll}]
DescentHold[a_Plus]:=ReleaseHold@Map[DescentHold,Hold[a],{2}]
DescentHold[a_]:=Hold[a]

Note that this one approaches the outer Holds once the insides are wrapped, so that for instance the flatness of Plus kicks in:

DescentHold[2*3+(4+5)]
Out[4]= Hold[4]+Hold[5]+Hold[2*3]
过气美图社 2024-09-14 00:55:56

使用 答案,作者:Michael Pilat,可以写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]

Using the idea about ReplacePart and Extract functions from the answer by Michael Pilat, one can write HoldAndEvaluate function, which allows him to evaluate a desired part of the expression without the need to calculate its position (it can be marked with "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]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文