Leonid在他的书的第四章中写道:“...模块,块和With。这些结构在Mathematica Book和Mathematica Help中有详细解释,所以我在这里只说几句。... “
从我所读过的(能够找到)我仍然在黑暗中。对于打包的函数我(简单地)使用Module,因为它可以工作,我知道构造。但它可能不是最好的选择。我(从文档中)不清楚何时,何地或为何使用With(或Block)。
答案 0 :(得分:30)
正如您所提到的,有许多事情需要考虑,可以进行详细讨论。但是我在大多数情况下应用了一些经验法则:
Module[{x}, ...]
是最安全的,可能需要
在评估模块期间,您希望避免破坏x的现有定义,或
现有的代码依赖于x undefined (例如代码Integrate[..., x]
)。
模块也是创建和返回新符号的唯一选择。特别是,出于这个原因,有时在高级动态编程中需要模块。
如果您确信没有重要的现有x定义或任何依赖于它的代码未定义,那么Block[{x}, ...]
通常会更快。 (请注意,在完全由您编写的项目中,对这些条件充满信心是一种合理的“封装”标准,您可能希望执行该标准,因此在这些情况下,Block通常是一个合理的选择。)
With[{x = ...}, expr]
是唯一在Hold[...]
内注入x值的范围构造。这很有用也很重要。 With
可以比Block更快或更慢,具体取决于expr和所采用的特定评估路径。但是,With
不太灵活,因为您无法在expr中更改x的定义。
答案 1 :(得分:29)
Block
和Module
之间更实际的区别可以在这里看到:
Module[{x}, x]
Block[{x}, x]
(*
-> x$1979
x
*)
因此,如果您希望返回x
,则可以使用Block
。例如,
Plot[D[Sin[x], x], {x, 0, 10}]
不起作用;为了使它工作,人们可以使用
Plot[Block[{x}, D[Sin[x], x]], {x, 0, 10}]
(当然这不是理想的,它只是一个例子)。
另一种用法类似Block[{$RecursionLimit = 1000},...]
,暂时更改$RecursionLimit
(Module
在重命名$RecursionLimit
时无效。
还可以使用Block
来阻止某些内容的评估,例如
Block[{Sin}, Sin[.5]] // Trace
(*
-> {Block[{Sin},Sin[0.5]],Sin[0.5],0.479426}
*)
即返回Sin[0.5]
,仅在Block
执行完毕后才进行评估。这是因为Sin
中的Block
只是一个符号,而不是正弦函数。你甚至可以做像
Block[{Sin = Cos[#/4] &}, Sin[Pi]]
(*
-> 1/Sqrt[2]
*)
(使用Trace
查看其工作原理)。因此,您也可以使用Block
在本地重新定义内置函数:
Block[{Plus = Times}, 3 + 2]
(*
-> 6
*)
答案 2 :(得分:11)
我想提及有关Block
和Module
之间差异的官方文档,请访问http://reference.wolfram.com/mathematica/tutorial/BlocksComparedWithModules.html。
答案 3 :(得分:10)
安德鲁已经提供了一个非常全面的答案。我只想总结一下,Module
用于定义可以在函数定义范围内重新定义的局部变量,而With
用于定义局部常量,这不可能。您也无法根据在同一With
语句中设置的另一个局部常量的定义来定义局部常量,或者在定义的LHS上具有多个符号。也就是说,以下内容不起作用。
With[{{a,b}= OptionValue /@ {opt1,opt2} }, ...]
我倾向于使用Module
设置包含With
的复杂函数定义。我在With
内首先设置了所有局部常量,例如传递给函数的Length
数据,如果需要,则根据需要使用其他局部变量。原因是With
比你真正拥有常数而不是变量要快一点。