我陷入了两难境地,请使用以下用 ML 编写的代码:
val x = 1
fun f(y) = x + y
val x = 2
val y = 3
val z = f (x + y)
z 的值为 6。现在,如果我在 python 中编写相同的代码,z 的值为 7。两种语言都声称(实际上教授这些语言的教师声称)具有词法/静态范围。但看起来只有 ML 通过使用在调用 f 时定义 f 函数时创建的环境来拥有它
任何指针将不胜感激!
谢谢!
在 Python 中,闭包是按变量而不是按值。因此,当您x
在函数中引用时,它指的是最近分配给x
的值,而不是x
定义函数时的值。这会得到非直观的结果,如下所示:
adders = []
for x in range(10):
adders.append(lambda y: x+y)
您打算创建一个添加x
到值的函数列表,其中x
从 0...9 变化,但它们都添加 9,因为这是x
循环结束时的值。
您可以通过使用默认参数将名称绑定到函数定义时的值来覆盖它。
x = 1
f = lambda y, x=x: x + y # x inside f is now locked at 1
x = 2
y = 3
z = f(x + y)
在这个例子中,你甚至没有真正处理闭包:x
这里实际上是一个全局变量。在 Python 中,只有在另一个函数内部定义了一个函数,并且顶级或模块全局命名空间不是函数时,才能创建闭包。但同样的原则也适用:全局变量显然可以在函数定义后更改,所以如果你想在函数定义时“锁定”它的值,你可以使用默认参数。
在 ML 中——至少在 ML 的功能部分中——没有变量赋值之类的东西。一旦你声明了那个val x = 1
,你就不能改变那个的值x
。
但是,您可以做的是声明另一个x
. 当您说 时val x = 2
,您正在引入一个名为 的全新变量x
,它基本上只是隐藏了旧变量。但是该函数f
已经被定义为指向原始的x
,所以它不受影响。
ML 确实支持可变类型,可以像 Python 中的变量一样重新分配。但是它们与功能范式相差甚远,以至于您几乎没有任何理由使用它们。如果你想这样编程,Python 是一种更好的语言。