为什么 Mathematica 会破坏 Module 中的正常范围规则? [英] Why would Mathematica break normal scoping rules in Module?

查看:48
本文介绍了为什么 Mathematica 会破坏 Module 中的正常范围规则?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如最近的post 作用域在模块内无法按预期工作.

As was pointed out in a recent post scoping does not work as expected inside of Module.

该线程中的一个示例是:

An example from that thread is:

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

但以下内容几乎按预期工作.

But the following works almost as expected.

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

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

What language design consideration made wolfram choose this functionality?

请参阅 Jefromi 的第一条评论,我将 z 从局部变量更改为非局部变量,但忘记更改输出.它不会影响问题.

See Jefromi's first comment I changed z from being a local variable to not and forgot to change the output. It does not effect the problem.

Michael Pilat 的观点似乎是 Block 和 Module 具有不同的功能.我想我理解他的观点,但我认为这与我的问题是正交的.所以这里有一个更新.

Michael Pilat's point seems to be that Block and Module have different functions. I think I understand his point, but I think that it is orthogonal to my question. So here is an update.

我可以在笔记本中全局使用以下代码:

I can use the following code at the the global level in a notebook:

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

但是当我将相同的代码块放入 Module 并使 expr local 时,它会产生不同的输出.

But when I put the same code block into a Module and make expr local it produces a different output.

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

如果你跟踪上面的模块调用,你会发现 Set[f[z_], expr] 被重写为 Set[f[z$_,expr].现在这个 z->z$ 转换发生在 Set 的 lhs 和 rhs 上.然而,它发生在 expr 计算之前,这会导致与在全局级别获得的结果不同.

If you trace the above Module call you find that Set[f[z_], expr] is rewritten to Set[f[z$_,expr]. Now this z->z$ transformation happens on both the lhs and rhs of the Set. It however happens before expr is evaluated, which causes a different result then would be obtained at the global level.

转换 z->z$ 似乎只在 rhs 具有模块调用的局部符号时发生.

The transformation z->z$ only seems to happen when the rhs has a symbol local to the Module call.

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

Why does Mathematica choose to have this syntax change in a Module call? What language/implementation design tradeoffs exist here that made this decision.

推荐答案

我认为答案很简单,但很微妙:Module 是一个词法范围构造,Block 是一个动态范围结构.

I think the answer is pretty simple, but subtle: Module is a lexical scoping construct, and Block is a dynamic scoping construct.

文档中的与模块比较的块教程讨论了区别:

The Blocks Compared With Modules tutorial from the documentation discusses the distinction:

当使用词法作用域时,变量被视为程序中特定代码段的局部变量.在动态范围内,变量的值对于程序执行历史的一部分是局部的.在像 C 和 Java 这样的编译语言中,代码"和执行历史"之间有非常明显的区别.Mathematica 的符号性质使这种区别稍微不那么明显,因为代码"原则上可以在程序执行期间动态构建.

When lexical scoping is used, variables are treated as local to a particular section of the code in a program. In dynamic scoping, the values of variables are local to a part of the execution history of the program. In compiled languages like C and Java, there is a very clear distinction between "code" and "execution history". The symbolic nature of Mathematica makes this distinction slightly less clear, since "code" can in principle be built up dynamically during the execution of a program.

Module[vars, body] 所做的就是将模块执行时的表达式体的形式视为一个 Mathematica 程序的代码".然后,当任何 vars 明确出现在此代码"中时,它被认为是本地的.Block[vars, body] 不看表达式主体的形式.相反,在 body 的整个评估过程中,块使用变量的本地值.

What Module[vars, body] does is to treat the form of the expression body at the time when the module is executed as the "code" of a Mathematica program. Then when any of the vars explicitly appears in this "code", it is considered to be local. Block[vars, body] does not look at the form of the expression body. Instead, throughout the evaluation of body, the block uses local values for the vars.

它提供了这个简化的例子:

It offers this reduced example:

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

也许关键是要意识到Module 将模块主体中i 的所有实例替换为本地化版本(例如,i$1234>) 词法之前模块的任何主体被实际评估.

Perhaps the key point is to realize that Module replaces all instances of i in the module body with a localized version (e.g., i$1234) lexically, before any of the body of the module is actually evaluated.

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

Thus, the module body that's actually evaluated is i$1234 + m, then i$1234 + i^2, then a + i^2.

没有任何问题,BlockModule 旨在表现不同.

Nothing is broken, Block and Module are intended to behave differently.

这篇关于为什么 Mathematica 会破坏 Module 中的正常范围规则?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆