为什么 Mathematica 会打破模块中正常的作用域规则?
正如最近的 后范围界定在模块内部无法按预期工作。
该线程的一个示例是:
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 从局部变量更改为非局部变量,但忘记更改输出。它不会影响问题。
编辑2: Michael Pilat 的观点似乎是 Block 和 Module 具有不同的功能。我想我理解他的观点,但我认为这与我的问题正交。所以这里有一个更新。
我可以在笔记本中的全局级别使用以下代码:
expr = 2 z;
f[z_] = expr;
f[7]
(*output: 14*)
但是当我将相同的代码块放入模块并使 expr 本地化时,它会产生不同的输出。
Clear[f];
Module[{expr},
expr = 2 z;
f[z_] = expr;
f[7]]
(*output: 2z*)
如果跟踪上面的 Module 调用,您会发现 Set[f[z_], expr] 被重写为 Set[f[z$_,expr]。现在,这个 z->z$ 变换同时发生在集合的左轴和右轴上。然而,它发生在对 expr 求值之前,这会导致在全局级别获得不同的结果。
z->z$ 转换似乎仅在 rhs 具有模块调用本地符号时才会发生。
为什么 Mathematica 选择在模块调用中更改此语法?这里存在哪些语言/实现设计权衡来做出这个决定。
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*)
What language design consideration made wolfram choose this functionality?
Edit: 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.
Edit2:
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*)
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*)
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.
The transformation z->z$ only seems to happen when the rhs has a symbol local to the Module call.
Why does Mathematica choose to have this syntax change in a Module call? What language/implementation design tradeoffs exist here that made this decision.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为答案非常简单,但很微妙:
Module
是一个词法作用域构造,而Block
是一个动态作用域构造。文档中的块与模块比较教程讨论了区别:
它提供了这个简化的示例:
也许关键点是要认识到
Module
用本地化版本替换模块主体中i
的所有实例(例如,i$1234
) 词法上,在模块的任何主体被实际评估之前。因此,实际计算的模块主体是
i$1234 + m
,然后是i$1234 + i^2
,然后是a + i^2
。没有任何问题,
Block
和Module
旨在表现不同。I think the answer is pretty simple, but subtle:
Module
is a lexical scoping construct, andBlock
is a dynamic scoping construct.The Blocks Compared With Modules tutorial from the documentation discusses the distinction:
It offers this reduced example:
Perhaps the key point is to realize that
Module
replaces all instances ofi
in the module body with a localized version (e.g.,i$1234
) lexically, before any of the body of the module is actually evaluated.Thus, the module body that's actually evaluated is
i$1234 + m
, theni$1234 + i^2
, thena + i^2
.Nothing is broken,
Block
andModule
are intended to behave differently.根据文档,
模块
具有属性HoldAll
,这会导致Module
内的所有内容保持未计算状态,因此您的expr
在expr
之前不会计算为2 z
code> 被分配给f[z_]
。将第二个参数包装到
Evaluate
中的Module
似乎可以解决问题:此外,使用
Block
而不是Module
也可以:According to the documentation,
Module
has attributeHoldAll
, which causes everything inside theModule
to remain in an unevaluated state, so yourexpr
is not evaluated to2 z
beforeexpr
is assigned tof[z_]
.Wrapping the second argument to
Module
inEvaluate
seems to solve the problem:Also, using
Block
instead ofModule
works: