示例:
list:={ Plus[1,1], Times[2,3] }
查看list
时,我得到:
{2,6}
我希望保持它们不被评估(如上所述),以便list
返回
{ Plus[1,1], Times[2,3] }
后来我想按列表顺序评估这些函数,以获得
{2,6}
list
中未计算函数的数量事先是未知的。除了 Plus
外,用户定义的函数如 f[x_]
可以存储在 list
中。希望示例清晰明了。
最好的方法是什么?
示例:
list:={ Plus[1,1], Times[2,3] }
查看list
时,我得到:
{2,6}
我希望保持它们不被评估(如上所述),以便list
返回
{ Plus[1,1], Times[2,3] }
后来我想按列表顺序评估这些函数,以获得
{2,6}
list
中未计算函数的数量事先是未知的。除了 Plus
外,用户定义的函数如 f[x_]
可以存储在 list
中。最好的方式是将它们存储在Hold
中,而不是List
中,像这样:
In[255]:= f[x_] := x^2;
lh = Hold[Plus[1, 1], Times[2, 3], f[2]]
Out[256]= Hold[1 + 1, 2 3, f[2]]
通过这种方式,您可以完全控制它们。在某个时候,您可能需要调用ReleaseHold
以评估它们:
In[258]:= ReleaseHold@lh
Out[258]= Sequence[2, 6, 4]
如果你想要以列表的形式呈现结果而不是Sequence
,你可以使用List@@lh
。如果你需要评估一个特定的结果,只需使用Part
来提取它:
In[261]:= lh[[2]]
Out[261]= 6
如果您坚持使用该结构,这里有一种方法:
In[263]:= l:={Plus[1,1],Times[2,3],f[2]};
Hold[l]/.OwnValues[l]
Out[264]= Hold[{1+1,2 3,f[2]}]
编辑
如果您有一些带有UpValues
的函数/符号,即使在Hold
中也可以进行评估,您可能希望使用HoldComplete
代替Hold
。
编辑2
正如@Mr.Wizard在另一个答案中指出的那样,有时候您可能会发现在序列中单独包装每个项目的Hold
更加方便。我的评论是,一旦我们意识到很容易将一个形式转换为另一个形式并返回,两种形式的有用性就会增强。以下函数将在Hold
中拆分序列为保持的项目列表:
splitHeldSequence[Hold[seq___], f_: Hold] := List @@ Map[f, Hold[seq]]
In[274]:= splitHeldSequence[Hold[1 + 1, 2 + 2]]
Out[274]= {Hold[1 + 1], Hold[2 + 2]}
Hold
甚至更容易——只需应用Join
:
In[275]:= Join @@ {Hold[1 + 1], Hold[2 + 2]}
Out[275]= Hold[1 + 1, 2 + 2]
Union
、Select
、Cases
等内容,而不必过多考虑评估。完成后,您可以将它们合并成单个Hold
,例如将其作为未评估的参数序列提供给某些函数。
编辑3
根据@ndroock1的要求,这里有一个具体的例子。设置如下:
l = {1, 1, 1, 2, 4, 8, 3, 9, 27}
S[n_] := Module[{}, l[[n]] = l[[n]] + 1; l]
Z[n_] := Module[{}, l[[n]] = 0; l]
Hold
中:In[43]:= held = Hold[Z[1], S[1]]
Out[43]= Hold[Z[1], S[1]]
以下是 exec
函数的示例:
exec[n_] := MapAt[Evaluate, held, n]
In[46]:= {exec[1], exec[2]}
Out[46]= {Hold[{0, 1, 1, 2, 4, 8, 3, 9, 27}, S[1]], Hold[Z[1], {1, 1, 1, 2, 4, 8, 3, 9, 27}]}
held
保持不变,因为我们在副本上操作。还要注意,原始设置包含可变状态(l
),这在Mathematica中不是很惯用。特别是,评估的顺序很重要:In[61]:= Reverse[{exec[2], exec[1]}]
Out[61]= {Hold[{0, 1, 1, 2, 4, 8, 3, 9, 27}, S[1]], Hold[Z[1], {2, 1, 1, 2, 4, 8, 3, 9, 27}]}
exec
是根据请求规范实现的,但它隐含地依赖于全局变量l
,我认为这是一个不好的实践。In[64]:= execAlt[n_] := MapAt[ReleaseHold, listOfHeld, n]
In[70]:= l = {1, 1, 1, 2, 4, 8, 3, 9, 27} ;
{execAlt[1], execAlt[2]}
Out[71]= {{{0, 1, 1, 2, 4, 8, 3, 9, 27}, Hold[S[1]]}, {Hold[Z[1]], {1, 1, 1, 2, 4, 8, 3, 9, 27}}}
getType[n_, lh_] := lh[[n]] /. {Hold[_Z] :> zType, Hold[_S] :> sType, _ :> unknownType}
In[172]:= getType[#, listOfHeld] & /@ {1, 2}
Out[172]= {zType, sType}
List
,而是使用类似于下面这样的东西: SetAttributes[lst, HoldAll];
heldL=lst[Plus[1, 1], Times[2, 3]]
Hold
:a = {Hold[2 + 2], Hold[2*3]}
如果您想要列表的外观而不显示 Hold
,则可以在元素或列表上使用 HoldForm
:
b = {HoldForm[2 + 2], HoldForm[2*3]}
c = HoldForm@{2 + 2, 2*3}
{2 + 2, 2 * 3}你可以使用
ReleaseHold
恢复计算后的表达式。a // ReleaseHold
b // ReleaseHold
c // ReleaseHold
Out[8]= {4, 6}
Out[9]= {4, 6}
Out[10]= {4, 6}
表单Hold[2+2, 2*3]
或者像上面的a
和b
一样是很好的,因为你可以轻松地添加项,例如使用Append
。对于b
类型,它在逻辑上是:
Append[b, HoldForm[8/4]]
For Hold[2+2, 2*3]
:
Hold[2+2, 2*3] ~Join~ Hold[8/4]
lh = Function[u, Hold@u, {HoldAll, Listable}];
k = lh@{2 + 2, Sin[Pi]}
(*
->{Hold[2 + 2], Hold[Sin[\[Pi]]]}
*)
ReleaseHold@First@k
(*
-> 4
*)