22

我已经编程了很长时间(实际上太长了),但我真的很难掌握“自由变量”和“绑定变量”这两个术语。

我在网上找到的大多数“解释”都是从谈论诸如 Lambda 演算和形式逻辑或公理语义之类的话题开始的。这让我想去拿我的左轮手枪

有人可以从实现的角度解释这两个术语吗?它们可以存在于编译语言中,它们翻译成什么低级代码?

4

2 回答 2

24

自由变量是在某些函数中使用的变量,其值取决于调用、调用或使用函数的上下文。例如,在数学术语中,z是一个自由变量,因为它不受任何参数的限制。x是有界变量

f(x) = x * z

编程语言术语中,自由变量是在运行时动态确定的,在函数调用堆栈上向后搜索变量的名称。

界变量评估不依赖于函数调用的上下文。这是最常见的现代编程语言变量类型。局部变量、全局变量和参数都是有界变量。

自由变量有点类似于一些古老编程语言的“按名称传递”约定。

假设您有一个f只打印一些变量的函数:

def f():
    print(X)

这是 Python。虽然X不是局部变量,但它的值遵循 Python 约定:它在定义函数的块链上向上搜索,直到到达顶层模块。

由于在 Python 中 的值X是由函数声明上下文决定的,所以我们说它X是一个有界变量。

假设,如果X是一个自由变量,这应该打印 10:

X = 2

def f():
    print(X)

def g():
    # X is a local variable to g, shadowing the global X
    X = 10
    f()

在 Python 中,此代码打印 2,因为这两个X变量都是有界的。局部X变量 ong绑定为局部变量,而 onf绑定到全局变量X

执行

使用自由变量的编程语言的实现需要注意每个函数被调用的上下文,并且对于每个自由变量使用一些反射来查找要使用的变量。

自由变量的值通常不能在编译时确定,因为很大程度上取决于运行时流程和调用堆栈。

于 2014-02-18T14:09:35.030 回答
13

变量是自由的还是绑定的都是相对的;这取决于您正在查看的代码片段。

在这个片段中,x被绑定:

function(x) {return x + x;};

在这里,x免费发生:

return x + x;

换句话说,自由度是上下文的属性。您没有说“ x是一个自由变量”或“ x是一个绑定变量”,而是确定您正在谈论的上下文:“ x在表达式E中是自由的”。因此,同一个变量x可以是自由的也可以是绑定的,具体取决于您所讨论的代码片段。如果片段包含变量的绑定站点(例如,它在函数参数中列出),那么它是绑定的,如果没有,它是免费的。

从实现的角度来看,自由/绑定区别很重要的地方是当您实现变量替换的工作方式时(例如,当您将参数应用于函数时会发生什么。)考虑评估步骤:

(function(x) {return x + x;})(3);
=> 3 + 3
=> 6

这很好用,因为x在函数体中是免费的。然而,如果x被绑定在函数体中,我们的评估需要小心:

(function(x) {return (function(x){return x * 2;})(x + x);})(3);
=> (function(x){return x * 2;})(3 + 3); // careful to leave this x alone for now!
=> (function(x){return x * 2;})(6);
=> 6 * 2
=> 12

如果我们的实现没有检查绑定事件,它可能已经替换了绑定 x3并给了我们错误的答案:

(function(x) {return (function(x){return x * 2;})(x + x);})(3);
=> (function(x){return 3 * 2;})(3 + 3); // Bad! We substituted for a bound x!
=> (function(x){return 3 * 2;})(6);
=> 3 * 2
=> 6

此外,应该澄清的是,自由与绑定是语法(即代码本身)的属性,而不是在运行时如何评估代码的属性。vz0 讨论动态范围的变量,它与自由变量有些相关,但不是同义词。正如 vz0 正确描述的那样,动态变量范围是一种语言功能,它允许通过查看运行时调用堆栈来评估包含自由变量的表达式,以找到共享相同名称的变量的值。然而,在不允许动态范围的语言中谈论自由出现的变量仍然是有意义的:如果你试图在这些语言中评估这样的表达式,你只会得到一个错误(比如“ x未定义”)语言。

而且我无法克制自己:我希望有一天,当人们提到 lambda 演算时,你能找到把左轮手枪收起来的力量!Lambda 演算是考虑变量和绑定的好工具,因为它是一种极简的编程语言,只支持变量和替换,仅此而已。现实世界的编程语言包含许多其他垃圾(例如动态范围),它们掩盖了本质。

于 2015-11-29T22:10:53.660 回答