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

nil*_*ock 37 wolfram-mathematica

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

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

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

And*_*lan 30

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

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

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

  2. 现有的代码依赖于未定义的 x (例如代码Integrate[..., x]).

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

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

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

  • +1一个不错的总结!我只有两条评论:首先,如果我们同意`Rule`和`RuleDelayed`是作用域构造(它们在某些方面),它们会给出另一种(非等效的)注入内部表达式的方法.其次,我不会*使用`Block`进行简单的封装,除非完全需要它的动态范围功能 - 很难对执行堆栈的某些部分负责,特别是如果你将函数作为参数传递,其中任意代码可能是执行.现在使用"Block"的小速度改进可能会导致后来非常微妙的错误. (4认同)

acl*_*acl 30

之间一个更实际的差异Block,并Module可以在这里看到:

Module[{x}, x]
Block[{x}, x]
(*
-> x$1979
   x
*)
Run Code Online (Sandbox Code Playgroud)

所以,如果你想返回x,你可以使用Block.例如,

Plot[D[Sin[x], x], {x, 0, 10}]
Run Code Online (Sandbox Code Playgroud)

不起作用; 为了使它工作,人们可以使用

Plot[Block[{x}, D[Sin[x], x]], {x, 0, 10}]
Run Code Online (Sandbox Code Playgroud)

(当然这不是理想的,它只是一个例子).

另一个用途是类似的Block[{$RecursionLimit = 1000},...],它会暂时改变$RecursionLimit(Module在重命名时不会起作用$RecursionLimit).

人们也可以Block用来阻止某事的评估,例如

Block[{Sin}, Sin[.5]] // Trace
(*
-> {Block[{Sin},Sin[0.5]],Sin[0.5],0.479426}
*)
Run Code Online (Sandbox Code Playgroud)

即返回Sin[0.5]仅在Block执行完毕后才进行评估.这是因为Sin里面Block只是一个符号,而不是正弦函数.你甚至可以做类似的事情

Block[{Sin = Cos[#/4] &}, Sin[Pi]]
(*
-> 1/Sqrt[2]
*)
Run Code Online (Sandbox Code Playgroud)

(Trace用来看看它是如何工作的).因此,您也可以使用Block本地重新定义内置函数:

Block[{Plus = Times}, 3 + 2]
(*
-> 6
*)
Run Code Online (Sandbox Code Playgroud)

  • 关于您的“Plot”示例。我相信“Plot”有一些启发式方法来决定是在数值替换“x”之前还是仅在之后评估其参数。使用“Block”的唯一区别是“Plot”评估其参数的时间发生变化。它没有说明“Block”是如何工作的。您可以通过在“Plot”参数中包含“Print[x]”语句来验证这一点。(在“Plot”中将未记录的“Evaluated”选项设置为“False”似乎不起作用。) (3认同)
  • $ RecursionLimit的示例非常有用. (2认同)
  • 我的观点是,“情节”的问题在于对论证的评估。使其工作的正确方法是“Plot[Evaluate[...], ...]”。事实上,将参数包装在“Block”中也修复了它,这只是偶然的,这是由于“Plot”的内部启发式决定评估顺序。 (2认同)

Men*_* Lu 11

我想提上的区别的官方文档BlockModule可在http://reference.wolfram.com/mathematica/tutorial/BlocksComparedWithModules.html.


Ver*_*eia 10

安德鲁已经提供了一个非常全面的答案.我只想总结一下,它Module是用于定义可以在函数定义范围内重新定义的局部变量,With而是用于定义局部常量,而不是.您也无法根据在同一With语句中设置的另一个局部常量的定义来定义局部常量,或者在定义的LHS上具有多个符号.也就是说,以下不起作用.

With[{{a,b}= OptionValue /@ {opt1,opt2} }, ...]
Run Code Online (Sandbox Code Playgroud)

我倾向于设置复杂的函数定义, Module并附上一个With.我设置了我可以在里面的所有局部常量With,例如Length传递给函数的数据,如果需要,那么根据需要设置其他局部变量.原因是,With你真的有一些常数而不是变量.