【问题标题】:Evaluate beyond one level within Hold in Mathematica在 Mathematica 中的 Hold 中评估超过一个级别
【发布时间】:2010-06-28 22:28:27
【问题描述】:

Evaluate at possible issues 上的mathematica 文档说:

Evaluate 只对第一个起作用 级别,直接在一个保持函数中

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

按住[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 使所有内容在第一级及之后都未进行评估。 目标是使用连续的 Hold、ReleaseHold 和 Evaluate 函数来控制从最内层嵌套函数到外层函数的每个阶段的表达式求值。我知道我可以使用 trace 来查看表达式中超出级别 1 的情况,但这会有所不同,有时使用较长的表达式来阅读会很复杂。

似乎唯一的方法是使用 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 等待时,它会在后台计算较低的级别。

【问题讨论】:

标签: wolfram-mathematica


【解决方案1】:

我无法给出Evaluate“仅在第一级工作,直接在持有的函数内”的确切原因,但我怀疑这部分是为了提高效率,因为如果评估者必须扫描完整的文件,它会很慢保存参数的表达式树传递给任何具有 Hold* 属性的函数,用于嵌套 Evaluate 表达式并计算它们,然后递归并在它刚刚计算的内容中查找 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,但结果不同,因为我们只进行部分评估,而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!

【讨论】:

  • 感谢您的帮助。上面的第一个函数示例简单而巧妙。它从hold控制下的表达式中提取出你想要的表达式部分;现在它超出了保持范围,因此对其进行评估,然后将其放回原来的位置。我打算以更长更复杂的方式尝试一些东西。
【解决方案2】:

当您想在 Mathematica 中做一些棘手的事情时,通常情况下,模式匹配和规则替换会派上用场。但是,在这种情况下,您必须使用something weird,并且您必须使用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]

规则实际上是a documented way在测试匹配和With结构体的主体之间共享局部变量;在这里,您不对局部变量做任何事情,而是强制以迂回的方式对其进行评估——因为较少的迂回方式行不通!

编辑添加:我认为您误解了Level 的结果;这个表达式的{2}级别的两个表达式是2Plus[2, 2];你可以通过使用可选的第三个参数来看到这一点,它的作用类似于Extract 的可选第三个参数:

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

使用{2} 级别规范,Replace 将尝试匹配并替换这两个表达式的规则,并且它将适用于第二个表达式。

【讨论】:

  • @dbjohn:我希望我的编辑回答了这个问题;如果不是,我认为这可能值得自己提出一个问题。
  • 我可以看到它如何在级别 2 上工作。相同的模式不应该在级别 3 上匹配吗?哪里有 Plus 的负责人可以匹配和替换,或者功能 Plus 在这个级别上不是“活跃”的?
  • @dbjohn:不。 Plus 在第 3 层弹出的原因是因为 Heads -> True 设置;您会看到 symbol Plus,它是表单 Plus[2, 2] 的头部,处于第 3 级(就像两个 2 一样),但 expr_Plus 只会匹配带有头部的表达式Plus,而不是 Plus 本身!
  • 我想我理解我可能需要以树的形式查看级别,而不是完整表达式的线性行。位于级别 3 的子节点/参数的根/头/父节点(例如 Plus)实际上位于级别 2。因此,直到评估器从获取级别 3 的参数返回到级别 2 是表达式 @987654345 @ 形成并准备好被识别以进行模式匹配。此已形成的表达式存在于级别 2 上,但级别 2 上的另一个子节点在级别 1 上的头部为 Plus 尚未形成其头部要被识别以进行模式匹配的表达式。对吗?
【解决方案3】:

一种不涉及Extract的技术是将Hold内部的部分包裹在内部Holds中,然后释放外部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]

请注意,一旦内部被包裹,这个就会接近外部Holds,例如Plus 的平整度就会发挥作用:

DescentHold[2*3+(4+5)]
Out[4]= Hold[4]+Hold[5]+Hold[2*3]

【讨论】:

    【解决方案4】:

    使用来自Michael Pilatanswer 中关于ReplacePartExtract 函数的想法,可以编写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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-23
      • 1970-01-01
      • 2020-09-06
      • 1970-01-01
      相关资源
      最近更新 更多