代码之家  ›  专栏  ›  技术社区  ›  Davorak

为什么Mathematica会破坏模块中的正常作用域规则?

  •  7
  • Davorak  · 技术社区  · 14 年前

    post 作用域在模块内部无法按预期工作。

    Module[{expr},
     expr = 2 z;
      f[z_] = expr;
      f[7]]
    (*2 z*)
    

    但以下工作几乎如预期。

    Module[{expr},
     expr = 2 z;
      Set@@{f[z_], expr};
      f[7]]
    (*14*)
    

    是什么语言设计考虑使wolfram选择了这个功能?

    编辑:请参阅Jefromi的第一个注释,我将z从一个局部变量更改为not,忘记更改输出。这不会影响问题的解决。

    编辑2:

    expr = 2 z;
    f[z_] = expr;
    f[7]
    (*output: 14*)
    

    Clear[f];
    Module[{expr},
     expr = 2 z;
     f[z_] = expr;
     f[7]]
    (*output: 2z*)
    

    如果您跟踪上面的模块调用,您会发现集合[f[z\u],expr]被重写为集合[f[z$\u,expr]。现在这个z->z$转换同时发生在集合的左/右上。然而,在计算expr之前会发生这种情况,这会导致在全局级别上获得不同的结果。

    转换z->z$似乎只在rhs具有模块调用的本地符号时发生。

    为什么Mathematica选择在模块调用中更改此语法?做出这一决定的语言/实现设计权衡是什么。

    2 回复  |  直到 7 年前
        1
  •  5
  •   Michael Pilat    14 年前

    我认为答案很简单,但很微妙: Module Block

    这个 Blocks Compared With Modules 文档中的教程讨论了以下区别:

    在C和Java这样的编译语言中,“代码”和“执行历史”有着非常明显的区别。Mathematica的符号特性使得这种区别稍微不那么明显,因为“代码”原则上可以在程序执行期间动态构建。

    什么 Module[vars, body] 将执行模块时表达式体的形式视为Mathematica程序的“代码”。然后,当任何变量显式地出现在这个“代码”中时,它被认为是本地的。 Block[vars, body] 不看表达式体的形式。相反,在body的整个求值过程中,块使用vars的局部值。

    它提供了一个简化的示例:

    In[1]:= m = i^2
    
    Out[1]= i^2
    
    (* The local value for i in the block is used throughout the evaluation of i+m. *)
    In[2]:= Block[{i = a}, i + m]
    
    Out[2]= a + a^2
    
    (* Here only the i that appears explicitly in i+m is treated as a local variable. *)
    In[3]:= Module[{i = a}, i + m]
    
    Out[3]= a + i^2
    

    模块 替换的所有实例 i i$1234 ) 词法上 , 模块的任何主体实际上都是求值的。

    因此,实际计算的模块体是 i$1234 + m ,然后 i$1234 + i^2 ,然后 a + i^2 .

    什么都没坏, 模块

        2
  •  2
  •   Isaac    14 年前

    根据 the documentation , Module HoldAll ,这会导致 模块 保持未评估状态,所以 expr 未计算为 2 z 出口 分配给 f[z_] .

    将第二个参数包装为 模块 在里面 Evaluate 似乎解决了这个问题:

    In[1]:= Module[{expr}, Evaluate[expr = 2 z;
      f[z_] = expr;
      f[7]]]
    
    Out[1]= 14
    

    Block 而不是 模块

    In[2]:= Block[{expr = 2 z},
     f[z_] = expr;
     f[7]]
    
    Out[2]= 14