Wolfram mathematica 在Mathematica中评估超过一个级别

Wolfram mathematica 在Mathematica中评估超过一个级别,wolfram-mathematica,Wolfram Mathematica,mathematica关于评估可能出现的问题的文件说明: “评估”仅在第一个项目上有效 级别,直接位于保持功能内 为什么Mathematica有这个限制?因此,如果我有一个具有多个级别的表达式,请以这个简化的示例为例: 保持[Plus[Plus[2,2],2]] 现在,假设我想看看第二个加号的答案是什么,而不需要对它下面的任何级别进行评估。我尝试过不同的方法,例如: In[290]:= Hold[Plus[Evaluate[Plus[2, 2]], 2]] Out[290]= Hold[Eval

mathematica关于评估可能出现的问题的文件说明:

“评估”仅在第一个项目上有效 级别,直接位于保持功能内

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

保持[Plus[Plus[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函数来控制从最内层嵌套函数到外层嵌套函数的每个阶段对表达式的求值。我知道我可以使用trace来查看表达式中超出级别1的情况,但这是不同的,有时用较长的表达式读取会比较复杂

似乎唯一的方法是使用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会在你真正想让它等待的时候,在后台评估较低的级别

我无法给出
Evaluate
“仅在第一级,直接在保留函数中工作”的确切原因,但我怀疑这部分是效率问题,在这种情况下,如果计算器必须扫描传递给任何函数的持有参数的完整表达式树,并对嵌套的
Evaluate
表达式使用
Hold*
属性进行计算,然后在其刚刚计算的表达式中递归并查找
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]
这让我们来说明另一个原因,即考虑到以下涉及
i
的表达式,在作为参数传递给具有
Hold*
属性的函数的表达式中,
Evaluate
在任何级别都起作用可能没有意义:

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
之前评估了该表达式的第一部分,但是结果是不同的,因为我们只进行了部分评估,并且在评估子表达式设置
j
时,没有评估
i=2
。有时,这可能是你想要发生的事情,但通常不太可能

请记住,即使是第一级的
Evaluate
,也可能被具有属性
HoldAllComplete
的函数或使用
HoldAllComplete
的函数击败:

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}

一种不涉及
提取
的技术是将
保持
内部的零件包装在
保持
内部,然后释放外部的
保持

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

Out[2]= Hold[3]+Hold[1+2]
你可以在这个方向上玩各种各样的游戏,但因为我不知道你想做什么,所以很难具体说明。可能有用的方法是定义您自己的
保持
,使其以您希望的方式下降:

SetAttributes[DescentHold,{HoldAll}]
DescentHold[a_Plus]:=ReleaseHold@Map[DescentHold,Hold[a],{2}]
DescentHold[a_]:=Hold[a]
请注意,一旦内部被包裹,这一个接近外部的
保持
s,因此,例如
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]
规则实际上是在测试匹配和具有结构的
主体之间共享局部变量;在这里,您不需要对局部变量执行任何操作,而是以一种迂回的方式强制对其求值——因为不太迂回的方式是行不通的

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

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

{2}
级别规范中,
Replace
将尝试匹配并替换针对这两个表达式的规则,它将在第二个表达式上工作

使用关于
ReplacePart
Extract
函数的思想,可以编写
holdandeevaluate
函数,这允许他计算表达式的所需部分,而无需计算其位置(可以用“MyEvaluate”标记)


谢谢,这很有帮助。上面的第一个函数示例简单而巧妙。它从hold控制的表达式中提取您想要的表达式部分;现在它不在保持范围内,所以对其进行评估,然后将其放回原来的位置。我打算用一种更长更复杂的方式尝试一些东西。相关问题:@dbj
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]