Lambda 没有自由变量的语言

Lambda 没有自由变量的语言,lambda,functional-programming,scheme,closures,lisp,Lambda,Functional Programming,Scheme,Closures,Lisp,在阅读了“为什么FUNARG问题应该被称为环境问题”之后,我问了自己一个问题:如果我们禁止定义一个函数,那么会发生什么情况呢 (define (foo x) (+ a x)) 将不允许在顶级(因为没有要关闭的环境,包含),而 是允许的,因为返回的lambda可以创建闭包。 这里有两个问题: 1.这会如何影响语言的表达能力?是否有某些功能在此类限制下变得不可用?有人能举一个例子,当定义带有自由变量的函数时,它会很有用吗? 2.这是否意味着闭包中的所有环境变量现在都有静态和可预测的偏移量?正如Wi

在阅读了“为什么FUNARG问题应该被称为环境问题”之后,我问了自己一个问题:如果我们禁止定义一个函数,那么会发生什么情况呢

(define (foo x) (+ a x))
将不允许在顶级(因为没有要关闭的环境,包含),而

是允许的,因为返回的lambda可以创建闭包。 这里有两个问题:
1.这会如何影响语言的表达能力?是否有某些功能在此类限制下变得不可用?有人能举一个例子,当定义带有自由变量的函数时,它会很有用吗?
2.这是否意味着闭包中的所有环境变量现在都有静态和可预测的偏移量?

正如Will Ness和tfb所说,存在一个全局环境。在表达式中,
+
a
都是自由变量。重要的是定义
f
时,全局环境中是否存在
a
。 此外,“自由”或“束缚”是一个相对的概念

引用在任何环境中都没有绑定的词汇变量没有什么意义。我能想到的唯一一个例子是元编程,但这并不是真正相关的,因为在这种情况下,您只是将代码作为数据进行操作。当您最终生成一个表单并编译或计算它时,您仍然有一个词法范围,然后所有符号都必须解析为一个已知变量。 对于公共Lisp中的特殊变量,或者默认变量动态限定Emacs的作用域,引用自由变量是有意义的。在Emacs中,您甚至可以引用未声明的变量,而没有警告

这会如何影响语言的表达能力

因此,如果您不允许自由变量(不在任何词汇范围内绑定),则基本上不允许具有动态范围的变量(在常见的Lisp中,它们被定义为具有不确定范围和动态范围)。你失去了表达能力。例如,OCaml就是这样。但是,您仍然可以定义一个库来模拟它们,如和中所示

OCaml提供了一个新的绑定,它不仅使用词法作用域,而且禁止更改现有绑定

# let a = 10;;
val a : int = 10

# let f () = a;;
val f : unit -> int = <fun>

# let a = 20;;
val a : int = 20

# f ()
- : int = 10
#设a=10;;
val a:int=10
#设f()=a;;
val f:单位->整数=
#设a=20;;
val a:int=20
#f()
-:int=10
在这里,第二个
a
阴影覆盖了前一个
f
仍然是指前一个
a
函数也是如此,这就是为什么有一个
rec
关键字来定义递归函数和相互递归函数的原因。 这是一种与Lisp不同的方法,Lisp允许在运行时重新定义大多数内容

这是否意味着闭包中的所有环境变量现在都有静态和可预测的偏移量


词法作用域允许将变量编译到固定位置。是否这样做取决于您的工具。例如,在解释器中,您的环境可能保存在运行时数据结构中。

Scheme在Lisp中引入了词法范围和闭包,有效地解决了“环境问题”。现代Lisp,如Scheme/Racket、Common Lisp和Clojure都使用词法作用域,其工作原理与您描述的基本相同。然而,Emacs Lisp是一个有趣的Lisp示例,它仍然在使用,但默认情况下不使用词法范围。您应该看看超静态全局环境(请参见示例),如果我在OCaml中没有弄错的话,将使用超静态全局环境。即使是全局级别的重新定义也会影响现有绑定,并且不会更改现有代码的语义,这与Common Lisp这样的动态环境不同,在动态环境中,您可以轻松地重新定义函数。有一个环境需要关闭“全局”/“顶级”环境。问题是,它在重新定义变量时的行为——它是改变绑定(即它更改了以前对它们的所有引用)还是隐藏绑定(即它们“从现在起”生效)。另一个问题是,在REPL和/或正在编译的文件中做了什么…@AlexisKing如果顶级环境中没有变量,则无法关闭它。这就是重点,对吗?两个函数都使用自由变量(或顶级环境中绑定的变量):`+'。
# let a = 10;;
val a : int = 10

# let f () = a;;
val f : unit -> int = <fun>

# let a = 20;;
val a : int = 20

# f ()
- : int = 10