TL; DR正如其他人指出的那样:lambda表示法只是一种定义函数的方法,而不必强迫给它们命名。
长版
我想对此主题进行详细说明,因为我觉得它很有趣。免责声明:我很早以前就学习过lambda演算课程。如果知识更好的人发现我的答案有任何不正确之处,请随时帮助我进行改进。
让我们从表达式开始,例如1 + 2
和x + 2
。诸如1
和的文字2
称为常量,因为它们绑定到特定的固定值。
诸如变量之类的标识符x
称为变量,为了对其进行评估,您需要首先将其绑定到某个值。因此,基本上x + 1
,只要您不知道是什么,就无法进行评估x
。
lambda表示法提供了用于将特定输入值绑定到变量的架构。甲lambda表达式可以通过添加可形成λx .
在现有表达的前面,例如λx . x + 1
。变量x
被认为是自由的x + 1
和必然的λx . x + 1
这对评估表达式有何帮助?如果您向lambda表达式输入值,就像这样
(λx . x + 1) 2
那么您可以通过用x
值2 替换(绑定)所有出现的变量来评估整个表达式:
(λx . x + 1) 2
2 + 1
3
因此,lambda表示法提供了一种将事物绑定到出现在表达式/程序块中的变量的通用机制。根据上下文,这会在编程语言中创建明显不同的概念:
- 在像Haskell这样的纯函数式语言中,lambda表达式表示数学意义上的函数:将输入值注入到lambda的主体中,并产生输出值。
- 在许多语言(例如JavaScript,Python,Scheme)中,评估Lambda表达式的主体可能会产生副作用。在这种情况下,可以使用术语过程来标记纯功能的差异。
除了差异之外,lambda表示法是关于定义形式参数并将其绑定到实际参数。
下一步,就是给函数/过程起个名字。在几种语言中,函数都是与其他函数一样的值,因此可以给函数命名,如下所示:
(define f (lambda (x) (+ x 1))) ;; Scheme
f = \x -> x + 1 -- Haskell
val f: (Int => Int) = x => x + 1 // Scala
var f = function(x) { return x + 1 } // JavaScript
f = lambda x: x + 1 # Python
正如Eli Barzilay指出的那样,这些定义只是将名称绑定f
到一个值,而该值恰好是一个函数。因此,就此而言,函数,数字,字符串,字符都是可以以相同方式绑定到名称的值:
(define n 42) ;; Scheme
n = 42 -- Haskell
val n: Int = 42 // Scala
var n = 42 // JavaScript
n = 42 # Python
在这些语言中,您还可以使用更熟悉(但等效)的符号将函数绑定到名称:
(define (f x) (+ x 1)) ;; Scheme
f x = x + 1 -- Haskell
def f(x: Int): Int = x + 1 // Scala
function f(x) { return x + 1 } // JavaScript
def f(x): return x + 1 # Python
某些语言(例如C)仅支持后者的符号来定义(命名)函数。
关闭
关于闭包的最终结论。考虑一下表达式x + y
。它包含两个自由变量。如果x
使用lambda表示法进行绑定,则会得到:
\x -> x + y
这还不是一个函数,因为它仍然包含一个free变量y
。您也可以通过绑定来实现一个功能y
:
\x -> \y -> x + y
要么
\x y -> x + y
与+
功能相同。
但是您可以y
用另一种方式(*)进行绑定:
incrementBy y = \x -> x + y
将函数increasingBy应用于数字的结果是闭包,即函数/过程,其主体包含一个自由变量(例如y
),该变量已绑定到定义了闭包的环境中的值。
因此,incrementBy 5
是由5递增的数字功能(关闭)。
注意 (*)
我在这里有点作弊:
incrementBy y = \x -> x + y
相当于
incrementBy = \y -> \x -> x + y
因此绑定机制是相同的。直观地,我认为闭包代表了更复杂的lambda表达式的一部分。创建此表示形式时,已经设置了母表达式的某些绑定,并且闭包在稍后对其求值/调用时会使用它们。