为何定义教会的数字

时间:2017-02-01 11:24:38

标签: lambda-calculus

我想明白,教会为什么要定义数字:

0 = λ f . λ x . x
1 = λ f . λ x . f x
2 = λ f . λ x . f f x
3 = λ f . λ x . f f f x
4 = λ f . λ x . f f f f x

背后的逻辑是什么?

为什么0表示如下:

0 = λ f . λ x . x

3 个答案:

答案 0 :(得分:7)

教会并没有尝试实践。他试图证明关于lambda演算的表达能力的结果 - 原则上任何可能的计算都可以在lambda演算中完成,因此lambda演算可以作为可计算性研究的理论基础。为了做到这一点,有必要将编码数字作为lambda表达式,以便像后继函数这样的东西很容易定义。这是显示lambda演算和Gödel's recursive function theory(它是关于自然数的可计算函数)的等价性的关键步骤。教堂数字基本上是方便的,虽然不是非常可读的数字编码。从某种意义上说,它没有任何非常深刻的逻辑。声明并非本质上<1> λ f . λ x . f x,而后者是前者的可维护编码。

这并不意味着它是任意编码。它有一个明确的逻辑。编码数字n的最自然方式是涉及n。教会数字使用n函数应用程序。自然数n由高阶函数表示,该函数将函数n次应用于输入。 1由应用一次的函数编码,2由应用两次的函数编码,依此类推。这是一种非常自然的编码,尤其是在lambda演算的背景下。此外,很容易在它们上定义算术,这简化了lambda演算相当于递归函数的证明。

要在实践中看到这一点,您可以运行以下Python3脚本:

#some Church numerals:

ZERO = lambda f: lambda x: x
ONE = lambda f: lambda x: f(x)
TWO = lambda f: lambda x: f(f(x))
THREE = lambda f: lambda x: f(f(f(x)))

#function to apply these numerals to:

def square(x): return x**2

#so ZERO(square), ONE(square), etc. are functions
#apply these to 2 and print the results:

print(ZERO(square)(2), ONE(square)(2), TWO(square)(2),THREE(square)(2))

输出:

2 4 16 256

请注意,这些数字是通过将数字2分别平方0次,1次,2次和3次获得的。

答案 1 :(得分:6)

根据Peano axioms,对于另一个自然数 n ,自然数为0或 S n ):

0 = 0
1 = S(0)
2 = S(S(0))
...

您可以将教会数字视为Peano数字的概括,您可以在其中提供自己的0和 S

0 = λs.λz. z
1 = λs.λz. s(z)
2 = λs.λz. s(s(z))
...

由于这是一个编程论坛,让我们在EcmaScript 6中创建一些教会数字:

const ZERO = s => z => z;
const ONE  = s => z => s(z);
const TWO  = s => z => s(s(z));
...

您可以通过提供适当的零和后继来将这些教会数字转换为JavaScript数字:

function toInt(n) {
    return n(i => i + 1)(0);
}

然后:

> toInt(TWO)
2

您可以使用教会数字来做一些实际的事情:

function shout(text) {
    return text + "!";
}

> shout("hi")
"hi!"
> NINE(shout)("hi")
"hi!!!!!!!!!"

您可以在此处试用:https://es6console.com/iyoim5y8/

答案 2 :(得分:2)

以下paperRobert (Corky) Cartwright为我打破了它。

从一开始就要掌握的要点:

  • 所有教会数字都是具有两个参数的函数;
  • 在任何数字的教会代表中,暗示:
    • f - 是“继承者”功能(即接受教会数字并返回教会数字旁边的教会数字,它基本上是增量);
    • x - 是一个(教会数字)值,表示“零”(计数起点)。

牢记这一点:

λf . λx . x
如果我们将传递适当的f('后继'' - 增量函数)和x('零' - 计数起点),

将等于零。 在这种特殊情况下,将f传递给哪个函数并不重要,因为它从未应用

λf . λx . ZERO

这样:

λf . λx .  fx

将评估为1:

λf . λx . INCREMENT ZERO

以及以下内容:

λf . λx . f f x

将符合2:

λf . λx . INCREMENT(INCREMENT ZERO)

等等,对于所有连续的数字。

奖金(教会数字的加法,乘法和取幂):

这是一个Python代码片段,用于说明(并展开)上述内容:

ZERO = lambda f: lambda x: x
ONE = lambda f: lambda x: f(x)
TWO = lambda f: lambda x: f(f(x))
THREE = lambda f: lambda x: f(f(f(x)))

SUCC = lambda x: x + 1

ADD = lambda f: lambda x: lambda n: lambda m: n(f)(m(f)(x))
MULT = lambda f: lambda x: lambda n: lambda m: n(m(f))(x)
EXPON = lambda m: lambda n: n(m)

ADD利用了这样一个事实:任何教会数字都接受一个'零'计数起点,因为它的论点 - 从n开始,它只计入m。因此,ADD(SUCC)(0)(THREE)(TWO)只会计为3,但从2开始,因此会给我们2 + 1 + 1 + 1 = 5

MULT利用了这样一个事实,即“后继”函数只是教会数字的一个参数,因此可以被替换。因此,MULT(SUCC)(0)(TWO)(THREE)将返回3两次,这与2 * 3 = 6相同。

EXPON有点棘手(至少对我自己来说),关键的点是跟踪什么是返回的内容。它基本上是什么 - 使用教会数字表示的内在机制(特别是f应用的递归)。以下是一些例子:

3 0

EXPON(THREE)(ZERO)(SUCC)(0)
↓
lambda n: n(THREE)(ZERO)(SUCC)(0)
↓
ZERO(THREE)(SUCC)(0)
↓
lambda x: (SUCC)(0)
↓
SUCC(0)
↓
1

3 1

EXPON(THREE)(ONE)(SUCC)(0)
↓
lambda n: n(THREE)(ONE)(SUCC)(0)
↓
ONE(THREE)(SUCC)(0)
↓
lambda x: THREE(x)(SUCC)(0)
↓
THREE(SUCC)(0)
↓
3

1 3

EXPON(ONE)(THREE)(SUCC)(0)
↓
lambda n: n(ONE)(THREE)(SUCC)(0)
↓
THREE(ONE)(SUCC)(0)
↓
lambda x: ONE(ONE(ONE(x)))(SUCC)(0)
↓
ONE(ONE(ONE(SUCC)))(0)
↓
ONE(ONE(lambda x: SUCC(x)))(0)
↓
lambda x:(lambda x: (lambda x: SUCC(x)) (x))(x)(0)
↓
SUCC(0)
↓
1