Mathematica模块与With或Block - 指南,使用的经验法则?

时间:2011-07-12 08:27:17

标签: wolfram-mathematica

Leonid在他的书的第四章中写道:“...模块,块和With。这些结构在Mathematica Book和Mathematica Help中有详细解释,所以我在这里只说几句。... “

从我所读过的(能够找到)我仍然在黑暗中。对于打包的函数我(简单地)使用Module,因为它可以工作,我知道构造。但它可能不是最好的选择。我(从文档中)不清楚何时,何地或为何使用With(或Block)。

问题。是否有关于何时使用Module,With或Block(对于包中的功能)的经验法则/指南?与Module相比有限制吗?文档说With更快。我希望能够保护我的= choice = for Module(或其他构造)。

4 个答案:

答案 0 :(得分:30)

正如您所提到的,有许多事情需要考虑,可以进行详细讨论。但是我在大多数情况下应用了一些经验法则:

Module[{x}, ...]是最安全的,可能需要

  1. 在评估模块期间,您希望避免破坏x的现有定义,或

  2. 现有的代码依赖于x undefined (例如代码Integrate[..., x])。

  3. 模块也是创建和返回新符号的唯一选择。特别是,出于这个原因,有时在高级动态编程中需要模块。

    如果您确信没有重要的现有x定义或任何依赖于它的代码未定义,那么Block[{x}, ...]通常会更快。 (请注意,在完全由您编写的项目中,对这些条件充满信心是一种合理的“封装”标准,您可能希望执行该标准,因此在这些情况下,Block通常是一个合理的选择。)

    With[{x = ...}, expr]是唯一在Hold[...]内注入x值的范围构造。这很有用也很重要。 With可以比Block更快或更慢,具体取决于expr和所采用的特定评估路径。但是,With不太灵活,因为您无法在expr中更改x的定义。

答案 1 :(得分:29)

BlockModule之间更实际的区别可以在这里看到:

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},...],暂时更改$RecursionLimitModule在重命名$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)

我想提及有关BlockModule之间差异的官方文档,请访问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比你真正拥有常数而不是变量要快一点。