lambda - 没有自由变量的语言

标签 lambda functional-programming scheme closures lisp

在阅读“为什么 FUNARG 问题应该称为环境问题”之后,我问了自己一个问题:如果我们禁止定义一个无法创建闭包的函数,会发生什么,即

(define (foo x) (+ a x))

不会在顶层被允许(因为没有环境可以关闭,包含a),而

(define (bar a) (lambda (x) (+ a x))) 

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

最佳答案

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

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

How this may affect the expressiveness of the language?

因此,如果您不允许自由变量(未绑定(bind)在任何词法范围内),您基本上就是不允许具有动态范围的变量(在 Common Lisp 中,它们被定义为具有无限范围动态程度)。你失去了表达能力。例如,OCaml 就是这种情况。但是,您仍然可以定义一个库来模拟它们,如 Delimited Dynamic Binding 中所示。及其 implementation .

OCaml 提供了一个 hyper-static global environment ,它不仅使用词法作用域,而且禁止更改现有绑定(bind)。

# 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 隐藏了前一个,但是 f 仍然引用前一个 a函数也是如此,这就是为什么有rec关键字来定义递归和相互递归函数的原因。 这是一种不同于 Lisp 的方法,后者值得注意的是允许在运行时重新定义大部分内容。

Does this mean that all environment variables in closures have static and predictable offsets now?

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

关于lambda - 没有自由变量的语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37896091/

相关文章:

c++ - 传递带参数的 lambda

haskell - 调用函数的haskell案例

scheme - 协程是如何实现的?

list - Scheme/Racket/Lisp 中嵌套列表的 Minimax 操作?

haskell - 在 Haskell 中定义一个函数的 2 个或多个方程可以共享相同的 where/let block 吗?

scheme - Dr Racket列表功能

c++ - 通过右值引用返回 lambda?

ruby - 为什么我们需要纤维

java - 如何将 java.util.function.Predicate 实现为 Kotlin lambda?

scala - 编写功能代码,查找功能示例