lambda表达式与闭包的真正区别和联系

什么是lambda表达式

lambda和闭包最早可以追溯到lambda演算,lambda演算是上世纪30年代由Alonzo Church创造的。

lambda演算可以说是一种最简单的编程语言,你只可以用它来做的唯一的事情是:

  • 应用:将一个表达式应用到另一个表达式,表示f(x)。(把它当作是函数调用,其中f是函数,x是它的唯一参数)。
  • 抽象:它可以绑定一个符号,改符号可以看作是一个“插槽”、空白的框、或者说一个“变量”。它是用希腊字母λ(lambda)加上符号名称(例如x)跟着一个点,最后加上一个表达式组成。然后将表达式转换为期望一个参数的函数。
    例如:λx.x + 2表示包含一个x + 2的表达式,并且表示表达式中符号x是一个绑定变量(bound variable),它可以用你提供的值作为参数来替换。
    注意,这种方式定义的函数是匿名的,所以你还不能引用它,但是你可以立即调用它(看应用的定义),方式是提供它正在等待的参数,比如这样:(λx.x+ 2)7。然后,用表达式7(这种情况下是个字面值)被替换到x,作用在lambda子表达式x + 2上,所以你得到 7 + 2,最后你通过简单的算术规则得到9。

所以,我们解决了一个谜题:
lambda本质就是一个匿名函数,例如上面的λx.x + 2

在不同的编程语言中,函数抽象的语法可能不同,在JavaScript中是这样的:

function(x) { return x+2; }

现在你可以立即将参数应用到它,就像这样:

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

或者你可以将这个匿名函数(lambda)存储到某个变量:

var f = function(x) { return x+2; }

给他一个有效的名字f,允许引用它并在后面多次调用它,例如:

alert(  f(7) + f(10)  );   // should print 21 in the message box

什么是闭包

为了做到这一点,我们来谈谈lambda表达式中的符号(变量)。

正如我所说,lambda 抽象的的做法是在它的子表达式中绑定一个符号,以便它称为一个可替代的参数。这样的符号称为约束的(bound)。但是如果表达式中还有其他符号呢?例如λx.x/y+2。这这个表达式中,符号x是被lambda抽象λx约束的。但是另一个符号y不受限制,他是自由的。我们不知道它是什么以及它来自哪里,所以我们不知道它代表什么,有什么价值,因此我们不能评估(evaluate)这个表达式直到我们找出y代表的意义。

事实上,与其他两个符号2和+一样。虽然我们对这两个符号非常熟悉,但是计算机并不知道它们,我们需要通过在某处定义它们来告诉计算机它们的含义。例如,在库或在语言本身。

你可以想象自由符号是定义在表达式外面的地方,在它“周围的语境”(“surrounding context”)中,这称为环境(environment)。环境可能是一个更大的表达式,这是表达式的一部分。或者是在某个库,或者在语言本身(作为原生的)。

这让我们将lambda表达式分为两类:

  • CLOSED expressions:这些表达式中出现的每一个符号都受到一些lambda抽象的约束。换句话说,它们是自己自足的,不需要评估任何周边语境。它们也被称为Combinators。
  • OPEN expressions:这些表达式中的某些符号没有约束,也就是说,它们中的一些符号是自由的,它们需要一些外部信息,因此只有在提供这些符号的定义后才能对它们进行评估。
    你可以通过提供一个环境来关闭一个开放的lambda表达式,该环境通过将所有的自由符号绑定到某些值(可能是数字,字符串,匿名函数或者说lambda等)来定义它们。

然后这里是闭包的部分:
lambda表达式的闭包是定义在外部上下文(环境)中特定的符号集,它们给这个表达式中的自由符号赋值。它将一个开放的、仍然包含一些未定义的符号lambda表达式变为一个关闭的lambda表达式,使这个lambda表达式不再具有任何自由符号。

例如:你有一下这个lambda表达式:λx.x/y+2,符号x是受约束的,而y是自由的,因此这个表达式是开放的并且是不能被评估的,除非你说出y的意思(+和2也一样,是自由的)。假设你有一个环境,如下:

{  y: 3,  +: [built-in addition],  2: [built-in number],  q: 42,  w: 5  }

这个环境为我们的lambda表达式提供了所有未定义(自由)的符号y, + , 2,还有一些额外的符号q, w。而我们需要定义的是这个环境的子集:

{  y: 3,  +: [built-in addition],  2: [built-in number]  }

然后这个子集正是我们lambda表达式的闭包。

总结

lambda表达式的闭包是其环境中定义的一个子集,它给包含在lambda表达式中的自由变量赋值,从而有效的关闭表达式。(将一个开放的还不能评估的lambda表达式,转换成一个关闭的lambda表达式,然后可以进行评估,因为它包含的所有符号现在都已定义)。

参考资料

1.【闭包】你真的理解闭包和lambda表达式吗. https://www.jianshu.com/p/c22db2a91989

猜你喜欢

转载自blog.csdn.net/l460133921/article/details/82563235