Lambda演算如何加上数字?

Lambda演算如何加上数字?,lambda,functional-programming,lambda-calculus,Lambda,Functional Programming,Lambda Calculus,我一直在读关于lambda演算的书,喜欢它提出的想法,但有些事情我就是解释不了 lambda演算如何进行数字相加 我明白 (\x . + x x) 3 与3+3(即6)相同,但添加功能首先是如何实现的 它是编译器/语言必须内置的东西,还是可以由lambda演算单独定义?假设您使用的是加法,而不是一些基本的数字类型: \x \y . (\z . x(y(z))) 如果您向lambda演算中添加了某种基本数字类型,那么加法必须是基本的,或者必须按照类似后续操作的方式进行定义。是的,您可以在lam

我一直在读关于lambda演算的书,喜欢它提出的想法,但有些事情我就是解释不了

lambda演算如何进行数字相加

我明白

(\x . + x x) 3
3+3
(即
6
)相同,但添加功能首先是如何实现的

它是编译器/语言必须内置的东西,还是可以由lambda演算单独定义?

假设您使用的是加法,而不是一些基本的数字类型:

\x \y . (\z . x(y(z)))

如果您向lambda演算中添加了某种基本数字类型,那么加法必须是基本的,或者必须按照类似后续操作的方式进行定义。

是的,您可以在lambda演算中定义数字(实际上是任意数据类型)。这是我的想法

首先,让我们选择要定义的数字。最简单的数字是自然数:0、1、2、3等等。我们如何定义这些?通常的方法是使用:

  • 0是一个自然数
  • 如果n是一个自然数,那么Sn是一个自然数
  • 这里,S表示n的后继,或n+1。因此,前几个Peano自然数是0、S0、SS0、SSS0等等,这是一个一元表示

    现在,在lambda演算中,我们可以表示函数应用程序,所以我们可以表示Sn,但我们不知道如何表示0和S本身。但幸运的是,lambda演算为我们提供了一种推迟选择的方法:我们可以将它们作为参数,让其他人来决定!让我们为给定的0写z,为给定的s写s。然后,我们可以将前几个数字表示为:⟦N⟧ 对于“自然数n的lambda演算表示”:

    • ⟦0⟧ = λzs。z
    • ⟦1.⟧ = λzs。s z
    • ⟦2.⟧ = λzs。s(sz)
    • ⟦3.⟧ = λzs。s(s(s z))
    正如自然数n是S到0的n个应用一样,n的lambda演算表示是任何后继函数S到任何零z的n个副本的应用。我们也可以定义继任者:

    • ⟦0⟧ = λzs。z
    • ⟦s⟧ = λn。λzs。s(n z s)
    在这里,我们看到,在确保n使用相同的z和s之后,后继者将s的一个额外副本应用于n。我们可以看到,这给了我们相同的表示,使用⇝ 对于“评估为”:

    • ⟦0⟧ = λzs。z
    • ⟦1.⟧ = ⟦S0⟧
      =(λn.λz s.s(nz s))(λz′.z′)
      ⇝ λzs。s((λz′.z′)zs)
      ⇝ λzs。s z
    • ⟦2.⟧ = ⟦SS0⟧
      =(λn.λz s.s(nz s))((λn′.λz′.s′(n′z′))(λz〃s〃.z〃))
      ⇝ (λn.λzs.s(nzs))(λz′.s′((λz〃s〃.z〃)z′)
      ⇝ (λn.λzs.s(nzs))(λz′.s′.s′z′)
      ⇝ λzs。s((λz′s′.s′)zs)
      ⇝ λzs。s(sz)
    • ⟦3.⟧ = ⟦SSS0⟧
      =(λn.λz s.s(nz s))((λn′.λz′.s′(n′z′))((λn〃.λz〃s〃.s〃(n〃z〃s))(λz〃s〃.z〃)
      ⇝ (λn.λz s.s(nz s))((λn′.λz′.s′(n′z′))(λz〃s〃.s〃((λz′.s′)z〃s〃))
      ⇝ (λn.λz s.s(nz s))((λn′.λz′.s′(n′z′))(λz〃s〃.s〃z〃))
      ⇝ (λn.λz s.s(nz s))(λz′.s′((λz〃s〃.s〃z〃)z′)
      ⇝ (λn.λzs.s(nzs))(λz′s′.s′(s′z′))
      ⇝ λzs。s((λz′s′.s′(s′z′))zs)
      ⇝ λzs。s(s(s z))
    (是的,这会变得很难快速阅读。如果你觉得需要更多的练习,那么完成它是一个很好的练习——它会让我在我最初写的东西中发现一个错误!)

    现在,我们已经定义了0和S,这是一个好的开始,但我们也需要一个归纳原理。毕竟,这就是自然数的本质所在!那么,这将如何工作?事实证明我们基本上已经准备好了。当以编程的方式思考归纳原理时,我们需要一个函数,该函数以基本情况和归纳情况作为输入,并生成从自然数到某种输出的函数。我将把输出称为“n的证明”。那么我们的投入应该是:

  • 一个基本情况,这是我们对0的证明
  • 一种归纳案例,它是一个函数,它将n的证明作为输入,并生成Sn的证明
  • 换句话说,我们需要某种零值和某种后继函数。但这些只是我们的z和s参数!结果证明,我们把自然数表示为它们的归纳原理,我认为这很酷

    这意味着我们可以定义基本的操作。我将在这里定义加法,其余部分作为练习。在我们的归纳公式中,我们可以如下定义加法:

  • m+0=m
  • m+Sn=S(m+n)
  • 这是在第二个参数上归纳定义的。那么我们如何翻译呢?它变成:

    • ⟦+⟧ = λmn。λzs。n(mzs)s
    这是从哪里来的?我们把归纳原理应用于n。在基本情况下,我们返回m(使用环境z和s),如上所述。在归纳的情况下,我们将一个后继(环境s)应用到我们得到的东西上。所以这一定是对的

    另一种方法是,因为nzs将s的n个拷贝应用于z,我们得到n(mzs)s将s的n个拷贝应用于mzs,总共n+m个拷贝。同样,这是正确的答案

    (如果你仍然不相信,我鼓励你举出一个小例子,比如⟦1+2⟧; 它应该小到可以处理,但大到至少可以处理
     data Int = NonNeg Nat | NegSucc Nat
    
     data Pos = One
              | Twice     Pos
              | TwiceSucc Pos
    
     data Nat = Zero | PosNat Pos