将未评估的函数存储在mathematica列表中

时间:2011-06-06 15:44:39

标签: wolfram-mathematica

示例:

list:={ Plus[1,1], Times[2,3] }

在查看list时,我得到了

{2,6}

我想让他们不受评估(如上所述),以便list返回

{ Plus[1,1], Times[2,3] }

后来我想评估列表序列中的函数来获取

{2,6}

事先不知道list中未评估的函数数量。除Plus外,f[x_]等用户定义的函数可以存储在list

我希望这个例子很明确。

这样做的最佳方式是什么?

4 个答案:

答案 0 :(得分:10)

最好的方法是将它们存储在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

<强> EDIT2

正如@W.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更加容易 - 只需Apply Join

In[275]:= Join @@ {Hold[1 + 1], Hold[2 + 2]}

Out[275]= Hold[1 + 1, 2 + 2]

两种不同的形式在不同的情况下是有用的。您可以在保留项目列表中轻松使用UnionSelectCases等内容,而无需考虑评估。完成后,您可以将它们组合回单个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,我认为它是bad practice

存储由@ Mr.Wizard建议的函数的另一种方法可以实现,例如,像

在[63]中:= listOfHeld = splitHeldSequence [hold]

输出[63] = {保留[Z 1],按住[S 1]}

在这里

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}

答案 1 :(得分:7)

首先想到的是不使用List而是使用这样的东西:

 SetAttributes[lst, HoldAll];
 heldL=lst[Plus[1, 1], Times[2, 3]]

但肯定会有更多博学的建议!

答案 2 :(得分:5)

您还可以对要保留的每个元素使用Hold

a = {Hold[2 + 2], Hold[2*3]}

您可以在元素或列表中使用HoldForm,如果您希望列表的外观不可见Hold

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]或上面的ab表单很好,因为您可以轻松地添加以下内容: Append。对于b类型,逻辑上是:

Append[b, HoldForm[8/4]]

Hold[2+2, 2*3]

Hold[2+2, 2*3] ~Join~ Hold[8/4]

答案 3 :(得分:3)

另一种方式:

lh = Function[u, Hold@u, {HoldAll, Listable}];
k = lh@{2 + 2, Sin[Pi]}
(*
->{Hold[2 + 2], Hold[Sin[\[Pi]]]}
*)
ReleaseHold@First@k
(*
-> 4
*)