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

Wolfram mathematica Mathematica模块与With或Block-指南,使用经验法则?,wolfram-mathematica,Wolfram Mathematica,Leonid在他的书的第四章中写道:“……模块、块和With。这些构造在Mathematica书和Mathematica帮助中有详细的解释,所以我将在这里就它们说几句……” 从我所读到的(能找到的)来看,我仍然一无所知。对于打包函数,我(简单地)使用模块,因为它可以工作,而且我知道其构造。但这可能不是最好的选择。我(从文档中)不完全清楚何时、何地以及为什么要使用With(或Block) 问题。对于何时使用模块、With或Block(对于包中的函数),是否有经验法则/指南?与模块相比是否存在限制?

Leonid在他的书的第四章中写道:“……模块、块和With。这些构造在Mathematica书和Mathematica帮助中有详细的解释,所以我将在这里就它们说几句……”

从我所读到的(能找到的)来看,我仍然一无所知。对于打包函数,我(简单地)使用模块,因为它可以工作,而且我知道其构造。但这可能不是最好的选择。我(从文档中)不完全清楚何时、何地以及为什么要使用With(或Block)


问题。对于何时使用模块、With或Block(对于包中的函数),是否有经验法则/指南?与模块相比是否存在限制?医生们说,使用智能手机速度更快。我希望能够保护Me=选择=模块(或另一个构造)。

正如你提到的,有很多事情要考虑,并且详细的讨论是可能的。但这里有一些经验法则,我大部分时间都会用到:

Module[{x},…]
是最安全的,如果其中一个

  • 有一些x的现有定义,您希望避免在模块求值期间中断,或者

  • 存在依赖于未定义x的现有代码(例如
    Integrate[…,x]

  • 模块也是创建和返回新符号的唯一选择。特别是,由于这个原因,高级动态规划有时需要模块

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


    With[{x=…},expr]
    是唯一在
    Hold[…]内注入x值的作用域构造。这是有用和重要的<带
    的代码>可以比块快或慢,具体取决于expr和所采用的特定计算路径<但是,使用的code>灵活性较低,因为您无法在expr内更改x的定义。

    这里可以看到
    模块
    之间更实际的区别:

    Module[{x}, x]
    Block[{x}, x]
    (*
    -> x$1979
       x
    *)
    
    因此,如果希望返回eg
    x
    ,可以使用
    Block
    。比如说,

    Plot[D[Sin[x], x], {x, 0, 10}]
    
    不起作用;要使它发挥作用,可以使用

    Plot[Block[{x}, D[Sin[x], x]], {x, 0, 10}]
    
    (当然这并不理想,这只是一个例子)

    另一种用法类似于
    块[{$RecursionLimit=1000},…]
    ,它临时更改
    $RecursionLimit
    模块
    在重命名
    $RecursionLimit
    时不会工作)

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

    Block[{Sin}, Sin[.5]] // Trace
    (*
    -> {Block[{Sin},Sin[0.5]],Sin[0.5],0.479426}
    *)
    
    也就是说,它返回
    Sin[0.5]
    ,该值仅在
    完成执行后计算。这是因为
    块中的
    Sin
    只是一个符号,而不是正弦函数。你甚至可以这样做

    Block[{Sin = Cos[#/4] &}, Sin[Pi]]
    (*
    -> 1/Sqrt[2]
    *)
    
    (使用
    Trace
    查看其工作原理)。因此,您也可以使用
    Block
    在本地重新定义内置函数:

    Block[{Plus = Times}, 3 + 2]
    (*
    -> 6
    *)
    

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

    With[{{a,b}= OptionValue /@ {opt1,opt2} }, ...]
    

    我倾向于用
    模块
    来设置复杂的函数定义,并用
    封装一个
    。我首先使用
    中设置所有本地常量,例如传递给函数的数据的
    长度
    ,如果需要,然后根据需要设置其他本地变量。原因是,
    的结合要快一点,因为你确实有常数而不是变量。

    我想提一提关于
    模块
    之间区别的官方文档,可在上找到。

    根据你的例子,我尝试了这一点。清除[x];x=1;模块[{x},x]-它返回了(对我来说)意外的结果x$114。带有$RecursionLimit的示例非常有用。关于您带有
    绘图的示例
    。我相信
    Plot
    有一些启发性的方法来决定是在数值被
    x
    替换之前还是之后才对其参数求值。使用
    的唯一区别在于,当
    绘图
    将计算其参数时,会发生变化。它没有说明
    是如何工作的。您可以通过在
    Plot
    的参数中包含
    Print[x]
    语句来验证这一点。(在
    Plot
    中将未记录的
    Evaluated
    选项设置为
    False
    似乎不起作用。)我的观点是
    Plot
    的问题在于参数的计算。使其工作的正确方法是
    Plot[Evaluate[…],…]
    。将参数包装在
    中也解决了这一问题,这只是偶然的,是由于
    绘图
    的内部试探法决定了求值顺序。@ndroock1是什么让这件事出乎意料?其思想是,
    Module
    重命名其参数,因此它们不受
    Module
    正文外定义的影响实际上,(至少在v7中)您也不能根据
    Module
    中的其他变量定义局部变量,至少在定义阶段,即
    Module[{a=1,b=a},b]
    返回
    a
    块[{a=1,b=a},b]