【问题标题】:Store unevaluted function in list mathematica将未计算的函数存储在数学列表中
【发布时间】:2011-06-06 15:44:39
【问题描述】:

例子:

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

当查看list 时,我明白了

{2,6}

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

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

稍后我想评估列表序列中的函数以获得

{2,6}

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

我希望这个例子很清楚。

最好的方法是什么?

【问题讨论】:

    标签: wolfram-mathematica


    【解决方案1】:

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

    正如@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 更加容易 - 只需 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 建议的函数的另一种方法,例如喜欢

    In[63]:= listOfHeld = splitHeldSequence[held]

    输出[63]= {保持[Z1],保持[S1]}

    这里

    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}
    

    【讨论】:

    • 思路是:l = {1, 1, 1, 2, 4, 8, 3, 9, 27} S[n_] := Module[{}, l[[n]] = l[[n]] + 1; l] Z[n_] := 模块[{}, l[[n]] = 0; l] 然后我想将 {Z[1],S[1]} 存储在一个未评估的列表中。函数 exec[n_]:='在列表中位置 n 处执行函数'。我仍然无法使用 Hold 来解决这个问题。
    • @ndroock1 - 请查看我的编辑。如果可能的话,我会重新考虑设计,从不可变列表构建。
    • Edit 3 做到了。非常感谢你。 (我会用它来模拟 Cutland 的 URM(无限注册机),一个类似于图灵机的概念。)
    • @Leonid。还有一件事,后面存储和求值的原因是我想把指令打乱,需要一个跳转指令。这意味着我想评估 Held 中某个位置的函数类型,是 Z、S 还是其他? - 如果这是您的建议,我可以提出一个新问题。
    • @ndroock1 对于手头的情况,这很容易,请参阅我的编辑。这里有一些潜在的更一般的问题:“如何确定持有的表达式的类型而不评估它们,基于他们的头脑”,但你必须定义什么是类型等等。顺便说一句,尽量避免开始您的函数使用大写字母,这可能会导致与某些系统符号发生冲突。
    【解决方案2】:

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

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

    当然会有很多更博学的建议!

    【讨论】:

      【解决方案3】:

      您还可以在每个要保留的元素上使用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]
      

      【讨论】:

        【解决方案4】:

        另一种方式:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-07
          相关资源
          最近更新 更多