Wolfram mathematica 用于MapAll(/@)

Wolfram mathematica 用于MapAll(/@),wolfram-mathematica,Wolfram Mathematica,函数MapAll被认为非常重要,足以保证缩写形式/@,但我很少使用它,尤其是与我几乎到处使用的其他函数相比 哪些应用程序最能利用MapAll 它主要用于某些领域还是编程风格 与其他运营商相比,它的使用频率如何 我会将其用作一种惰性方法,在对象上应用代数表达式代数函数不适用于: In[13]:= ser = 1/(1 + x)^a + O[x]^4 Out[13]= SeriesData[x, 0, { 1, -a, Rational[1, 2] (a + a^2), Rational

函数
MapAll
被认为非常重要,足以保证缩写形式
/@
,但我很少使用它,尤其是与我几乎到处使用的其他函数相比

  • 哪些应用程序最能利用
    MapAll

  • 它主要用于某些领域还是编程风格

  • 与其他运营商相比,它的使用频率如何


我会将其用作一种惰性方法,在对象上应用代数表达式代数函数不适用于:

In[13]:= ser = 1/(1 + x)^a + O[x]^4

Out[13]= SeriesData[x, 0, {
 1, -a, Rational[1, 2] (a + a^2), 
  Rational[1, 6] ((-2) a - 3 a^2 - a^3)}, 0, 4, 1]

In[14]:= Factor[ser]

Out[14]= SeriesData[x, 0, {
 1, -a, Rational[1, 2] (a + a^2), 
  Rational[1, 6] ((-2) a - 3 a^2 - a^3)}, 0, 4, 1]

In[15]:= MapAll[Factor, ser]

Out[15]= SeriesData[x, 0, {
 1, -a, Rational[1, 2] a (1 + a), 
  Rational[-1, 6] a (1 + a) (2 + a)}, 0, 4, 1]

我不使用它,但是对于列表函数有一些有趣的行为。例如:

如果希望列表中的每个元素都有一个函数应用于它多次,这取决于它在列表中的嵌套深度,我想这是我唯一一次看到它被使用

SetAttributes[f, Listable]

(f //@ {{a}, {{b}}, c}) // Flatten
{f[f[f[a]]],f[f[f[f[b]]]],f[f[c]}
一般来说,尽管我认为您可以在任何时候使用ReplaceAll。

我曾多次使用它来生成代码的惰性表示,这些代码可能会执行,并且您希望在不进行任何计算的情况下对其进行转换或分解。以下是一个例子:

ClearAll[myHold, makeInertCode];
SetAttributes[{myHold, makeInertCode}, HoldAll];
makeInertCode[code_] :=
   MapAll[myHold, Unevaluated[code], Heads -> True]
In[27]:= 
icd = makeInertCode[
       With[{x  = RandomInteger[{1, 10}, 20]},
          Extract[x, Position[x, _?OddQ]]]
      ]

Out[27]= myHold[myHold[With][myHold[myHold[List][myHold[myHold[Set][myHold[x], 
myHold[myHold[RandomInteger][myHold[myHold[List][myHold[1],myHold[10]]],myHold[20]]]]]]],
myHold[myHold[Extract][myHold[x], myHold[myHold[Position][myHold[x], myHold[myHold[
PatternTest][myHold[myHold[Blank][]], myHold[OddQ]]]]]]]]]
以下是一个例子:

ClearAll[myHold, makeInertCode];
SetAttributes[{myHold, makeInertCode}, HoldAll];
makeInertCode[code_] :=
   MapAll[myHold, Unevaluated[code], Heads -> True]
In[27]:= 
icd = makeInertCode[
       With[{x  = RandomInteger[{1, 10}, 20]},
          Extract[x, Position[x, _?OddQ]]]
      ]

Out[27]= myHold[myHold[With][myHold[myHold[List][myHold[myHold[Set][myHold[x], 
myHold[myHold[RandomInteger][myHold[myHold[List][myHold[1],myHold[10]]],myHold[20]]]]]]],
myHold[myHold[Extract][myHold[x], myHold[myHold[Position][myHold[x], myHold[myHold[
PatternTest][myHold[myHold[Blank][]], myHold[OddQ]]]]]]]]]
现在,我们可以使用标准的解构工具,而不会有过早评估代码的危险(完全可以肯定,
myHold
可以被赋予
HoldAllComplete
属性,而不是
HoldAll
属性):

一旦代码被转换/解构,就可以将其包装在
Hold
HoldComplete
中,然后可以通过重复应用
myHold
等规则来删除
myHold
包装。但总体而言,MapAll的附加值在我看来相当有限,因为具有级别规范
{0,Infinity}
Map
与之等效。我不认为它经常被使用。

/@
是一种“后序树遍历”。它访问树结构中的每个节点,每个节点的子节点在节点本身之前被访问。调用提供的函数时,每个节点都作为其参数,该节点的子节点已被上一次调用“扩展”。树数据结构很常见,并且需要遍历它们。但我敢说,Mathematica上下文中
/@
的主要用例是实现评估器

让我们先创建一个随机树结构表达式:

In[1]:= 
        $expr = 500 //.
          n_Integer /; RandomInteger[100] < n :>
            RandomChoice[{p, m}] @@ RandomInteger[Floor[n/2], 2]
        $expr//TreeForm

Out[2]= p[m[p[34, 22], m[11, 24]], p[m[6, 7], 10]]
必须在每个规则中显式地编写对
eval1
的递归调用,这让人感到厌烦。此外,很容易忘记在规则中添加递归调用。现在考虑下面版本的相同的评估器:

In[8]:=
        eval2[p[a_, b_]] := a + b
        eval2[m[a_, b_]] := a - b
        eval2[a_] := a
递归调用的“噪音”已经消除,因此规则更易于阅读。当然,我们可以找到一些方法来自动插入必要的递归调用吗?输入
/@

In[11]:=
         eval2 //@ $expr
Out[11]= 78
这正是我们需要的。通过稍微滥用从函数式编程中借用的术语,我们可以说我们将
eval2
提升为递归下降函数。您可以在下图中看到效果

In[12]:=
         "eval2" //@ $expr // TreeForm

Postscript

在Mathematica中,总是有很多方法来达到效果。对于这个玩具评估者来说,前面的所有讨论都是多余的:

In[13]:=
         $expr /. {p -> Plus, m -> Subtract}

Out[13]= 78

。。。如果检查评估人员是否给出了正确的结果总是那么容易的话:)

我很难记住我是否使用过它……谢谢大家的回复。我很难选择要接受哪一个。今天我了解到,将O[x]^4添加到1/(1+x)^a会迫使后者进行系列扩展。然而,它就在文档中,隐藏在“Scope”标题下。@Sjoerd:这确实非常有用的一个应用程序是构造两个mma表达式(可以是代码)的差异。在mma的上下文中,这样的差异可能非常有用,比标准的基于字符串的差异更有用。我开始使用
MapAll
,但最后使用
MapIndexed
{0,Infinity}
作为diff,因为我还需要知道每个元素的级别。有趣。我一直在思考绘图注释问题()中的差异。您能否在原始绘图和带有注释的绘图之间进行差异,并将差异添加到第一个绘图的修订版本中?这样,这种保存注释的方法将比我的方法更能证明未来。@sjord您提到的任务听起来有些含糊不清,因为虽然我可以在两个图像之间进行区分,但我看不到一种不含糊的方法来对转换后的图像步骤进行“添加”。也许,这可以通过启发式的方法来实现,但我怀疑这是否可靠,除非对绘图格式施加一些额外的限制。+1个很好的例子!编写显式
eval
的替代方法是将mma计算器向正确的方向弯曲。我用于某种类似目的的一种技术是“代码冻结”——粗略地说,我动态地隐藏某些头部,以便它们在代码生成过程中保持惰性。结果是通过对初始代码的部分求值生成(或者说扩展)mma代码。但这与mma编译器的构建更相关,而不是评估员/口译员。
In[13]:=
         $expr /. {p -> Plus, m -> Subtract}

Out[13]= 78