这个讨论在之前的问题中出现过,我很想知道这两者之间的区别。最好用一个例子进行说明。
这是来自Leonid Shifrin的书Mathematica编程:高级介绍的一个示例。
ClearAll[a, b]
a = RandomInteger[{1, 10}];
b := RandomInteger[{1, 10}]
{4, 4, 4, 4, 4}
Table[b, {5}]
{10, 5, 2, 1, 3}
上面的示例可能会让人觉得,使用Set
创建符号的定义后,其值就是固定的,不会发生变化。但实际上并非如此。
f = ...
将表达式分配给f
,并在赋值时进行评估。如果符号仍然存在于已评估的表达式中,且稍后它们的值发生更改,则f
的显示值也会随之改变。
ClearAll[f, x]
f = 2 x;
f
2 x
x = 7;
f
14
x = 3;
f
6
记住规则在内部的存储方式是有用的。对于分配了一个值的符号 symbol = expression
,规则存储在OwnValues
中。通常情况下(但不总是),OwnValues
只包含一条规则。在这种特殊情况下,
In[84]:= OwnValues[f]
Out[84]= {HoldPattern[f] :> 2 x}
x
。对于评估来说,真正重要的是这种形式——规则在内部存储的方式。只要x
在赋值时没有任何值,无论是Set
还是SetDelayed
都会在全局规则库中产生(创建)相同的规则,这就是所有需要关注的。因此,在这个上下文中,它们是等效的。f
,因为它的计算值取决于当前x
的值。然而,这不是一个真正的函数,因为它没有任何参数,并且只触发符号x
的更改。通常情况下,应该避免使用这样的结构,因为隐式依赖于全局符号(变量)在Mathematica中和其他语言一样糟糕——它们使代码更难理解,而且漏洞更加微妙,更容易被忽视。相关讨论可以在这里找到。
Set
可以用于函数,有时候需要使用它。让我给你举个例子。这里Mathematica符号性地解决了和式,然后将其分配给aF(x),然后用于绘图。
ClearAll[aF, x]
aF[x_] = Sum[x^n Fibonacci[n], {n, 1, \[Infinity]}];
DiscretePlot[aF[x], {x, 1, 50}]
如果您尝试使用SetDelayed
,则需要将要绘制的每个值传递给Sum
函数。这不仅会慢得多,而且至少在Mathematica 7上会完全失败。ClearAll[aF, x]
aF[x_] := Sum[x^n Fibonacci[n], {n, 1, \[Infinity]}];
DiscretePlot[aF[x], {x, 1, 50}]
x
)的可能全局值不会干扰和被忽略,那么除了使用Clear
之外,另一种选择是在定义周围使用Block
。ClearAll[aF, x];
x = 1;
Block[{x}, aF[x_] = Sum[x^n Fibonacci[n], {n, 1, \[Infinity]}]];
查看函数的定义,可以确认我们得到了想要的结果:
?aF
Global`aF
aF[x_]=-(x/(-1+x+x^2))
In[1]:= Attributes[Set]
Out[1]= {HoldFirst, Protected, SequenceHold}
In[2]:= Attributes[SetDelayed]
Out[2]= {HoldAll, Protected, SequenceHold}
In[3]:= x = (Print["right hand side of Set"]; 3)
x
x
x
During evaluation of In[3]:= right hand side of Set
Out[3]= 3
Out[4]= 3
Out[5]= 3
Out[6]= 3
In[7]:= x := (Print["right hand side of SetDelayed"]; 3)
x
x
x
During evaluation of In[7]:= right hand side of SetDelayed
Out[8]= 3
During evaluation of In[7]:= right hand side of SetDelayed
Out[9]= 3
During evaluation of In[7]:= right hand side of SetDelayed
Out[10]= 3
x := (Print["right hand side of SetDelayed"]; 3)
这种构造方式,我给予加一的评价。这种技巧在调试时非常有用,可以看到规则何时被触发。 - Simon:=
用于定义函数,=
用于设置值。
例如,:=
在读取时会被计算,=
在设置时会被计算。
可以这样理解:
x = 2
y = x
z := x
x = 4
Evaluate
有帮助:DiscretePlot[aF[x] // Evaluate, {x, 1, 50}]
。 - Sjoerd C. de VriesSetDelayed
是正确的选择。那么为什么在这里使用Set
更好呢? - Jo Mo