在Mathematica中的Hold中评估超出一个级别

dbj*_*ohn 8 wolfram-mathematica

有关可能问题的评估的mathematica文档说:

评估仅在第一级工作,直接在保持的函数内

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

保持[加[加[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]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,第一个Hold将所有未评估的值保持在第一级以及超出第一级.目标是使用连续的Hold,ReleaseHold和Evaluate函数来控制从最内部嵌套函数到外部函数的每个阶段的表达式的评估,以实现该目标.我知道我可以使用trace来查看表达式中第一级以外发生的事情,但这种情况有所不同,有时候使用较长的表达式会很复杂.

似乎唯一的方法是使用Extract,Part或Level提取并完全拆除表达式到列表中; 评估我想要的部分表达; 然后为每个阶段重新构建并重新映射表达式.是否有其他方法或功能可以实现这一点我可以考虑?

编辑:这可能是一个更好的例子来看待释放第一次保持的方法.用表达式:

Hold[Plus[Plus[2, Plus[2,2]], 2]]]
Run Code Online (Sandbox Code Playgroud)

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

in = Plus[Plus[2, Hold[Plus[2,2]]], 2]]]
out = Hold[2+2]+4
Run Code Online (Sandbox Code Playgroud)

您发现当您真正希望它等待时,Mathematica将在后台评估较低级别.

Mic*_*lat 3

我无法给出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]
Run Code Online (Sandbox Code Playgroud)

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]
Run Code Online (Sandbox Code Playgroud)

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

请记住,即使Evaluate在第一级,也可以通过具有属性的函数HoldAllComplete或使用以下命令来击败HoldComplete

In[62]:= Hold[Evaluate[Plus[2,2]]]
Out[62]= Hold[4]
Run Code Online (Sandbox Code Playgroud)

...相对:

In[63]:= HoldComplete[Evaluate[Plus[2,2]]]
Out[63]= HoldComplete[Evaluate[2+2]]
Run Code Online (Sandbox Code Playgroud)

最后, 的输出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}
Run Code Online (Sandbox Code Playgroud)

哈!