一个 lambda(即一个函数)本身并不是很有趣。这是 JavaScript 中的一个函数:
function id(x) {
return x;
}
这个 JavaScript 程序是做什么的?什么都没有。
但是,函数具有可调用的危险特性。
当被调用时,函数可能会做任何事情(条件适用):
authorize_nuclear_attack(launch_codes); // oops
因此,平凡的 lambda 可以潜在地做任何事情。
想想看,每个 C 程序都是一个名为 main 的函数。
但是 Aadit,您需要一些其他语言功能来实现 lambda 的主体。
- 您将如何声明、定义、更新和评估变量?
- 如果不使用
if 语句,您将如何做出决定?
- 如何在没有
for 循环的情况下将一段代码重复任意次数?
- 如果没有排序运算符,您将如何编写顺序代码块?
- 如何在不使用基本
+ 运算符的情况下将两个数字相加?
怎么做?
的确如此。创建新函数(即 lambda 抽象)和调用函数(即 lambda 应用程序)的能力不足以编写整个程序。
然而,它已经足够接近了。
我们绝对需要编写任何程序(我的意思是任何程序)的唯一其他语言功能是获得变量的值(即评估)。
所有其他语言功能是:
- 这三个特性之一固有。
- 或者可以从这三个特征中派生出来。
让我们考虑一下:
-
声明变量的能力是 lambda 抽象所固有的:
function id(x) { // declare variable x
return x; // valuate variable x
}
-
定义变量(和更新即可视化递归)的能力是 lambda 应用程序所固有的:
id(something); // let x := something in the body of the function id
-
可以从 lambda 抽象和选择性评估中获得决策权:
function boolean_true(then_branch, else_branch) {
return then_branch;
}
function boolean_false(then_branch, else_branch) {
return else_branch;
}
function if_statement(boolean_condition, then_branch, else_branch) {
return boolean_condition(then_branch, else_branch);
}
-
重复的力量可以通过“吃自己的尾巴”来获得,如下:
function dragon(dragon) {
return dragon(dragon); // infinite loop
}
dragon(dragon);
我当然指的是衔尾蛇:
想象龙永远像轮子一样旋转,试图吃掉自己的尾巴。无限循环。
还可以使用选择性评估(也称为分支)创建终止循环。
-
序列运算的能力可以通过组合函数来获得:
function substitution(f, g) { // S combinator from SKI combinator calculus
return function (x) {
return f(x, g(x));
};
}
// substitution(f, g) is equivalent to (statement g; statement f)
// where the semicolon is the sequencing operator like in C
-
两个数字相加的能力可以通过将数字编码为函数来获得:
function zero(f, x) { // 0
return x;
}
function add1(n) { // n + 1
return function (f, x) {
return f(n(f, x));
};
}
function add(m, n) { // m + n
return function (f, x) {
return m(f, n(f, x));
};
}
重申一下,创建新函数的能力(即 lambda 抽象)、调用函数的能力(即 lambda 应用程序)和获取值的能力一个变量(即评估)一起允许您编写所有可以使用任何其他语言(例如 C 或 Java)编写的程序。
Lambda 演算抓住了可计算性的概念。
这意味着每个算法或半算法都可以用 lambda 演算表示(即每个可以解决的问题的解决方案或每个可以部分解决的问题的部分解决方案都可以用 lambda 演算表示) .
似乎 lambda 几乎可以用于任何事情(即使它看起来更复杂),但它确实有其局限性。
lambda 演算的唯一限制是您无法表达没有解决方案(甚至部分解决方案)的问题的解决方案。此类问题的一个示例是,“给定一个程序 P,P 会在所有输入上停止吗?”
换句话说,不可能编写一个函数H,如果P在所有输入上都停止,H(P) = true,否则H(P) = false。如果您确实设法编写了函数H,那么对于以下程序来说它总是不正确的:
function P(x) {
return H(P) ? P(x) : x;
}
如果H 认为P 总是停止,那么P 将进入无限循环。
如果H 认为P 并不总是停止,那么它总是停止。
lambda 没有涵盖哪些用例?
lambda 演算未涵盖的唯一用例是能够计算不可计算的函数。然而,由于不可计算的函数有点不可计算,我想说没有任何用例未被 lambda 演算所涵盖。
话虽如此,没有人使用 lambda 演算进行任何实际编程(就像没有人将图灵机用作实际计算机一样)。 λ 演算和图灵机的功率相等。但是,它们是截然不同的野兽。
大多数命令式编程语言(如 C 和 Java)都基于图灵机。大多数函数式编程语言(如 Haskell 和 OCaml)都基于 lambda 演算。一个好的程序员是其中一个方面的专家,但不是另一个方面的专家。优秀的程序员可以同时兼顾两者。