【Programming Languages And Lambda calculi】4.5 Lambda 表达式 数值编码

这篇博客探讨了Lambda演算中数值的Church编码,包括如何使用Church数表示自然数,以及如何通过函数操作实现加法(add1)、零检测(iszero)和减法(sub1)。此外,还提供了若干练习来证明这些操作的正确性。Lambda演算的这种编码方式展示了函数在数值计算中的强大应用,同时也揭示了在缺乏错误处理机制下可能遇到的问题,如sub1应用于0后的未定义行为。
摘要由CSDN通过智能技术生成

4.5 数值编码

在Lambda演算中,又很多给数值编码的方法,但是最流行的方法来自于Church,因此数值编码又被称为 Church 数。它的思想是一个自然数 n 被编码成一个有两个参数的函数,参数分别为 f 与 x,函数将f应用于x n遍。因此,0的函数接收一个 f 和 x,返回 x(相当于应用 f 0次)。1 的函数应用 f 一次,以此类推。
在这里插入图片描述

方法 add1 需要接收数值 n 的代表,并且生产出数值 n + 1的代表。换言之,它接收一个含有两个参数的函数并且返回另一个含有两个参数的函数;新的函数将应用它第一个参数于第二个参数 n + 1 次。为了使第一个 n 被应用,新函数应该使用旧的 n。
在这里插入图片描述

类似于 true 和 false 的编码,数值编码也很简便。为了对两个数值 n 和 m 使用加法,我们只需应用 add1 到 n 共 m 次 —— 而 m 恰巧是一个会接收 add1 并应用其 m 次的函数。
在这里插入图片描述

将数值作为函数的想法对定义 iszero 也十分有用,该函数接收数值后,如果数值为 0 则返回 true,其他返回 false;如果这个函数应用 0 次于 true,则结果为 true,其他情况则为 false。
在这里插入图片描述

为了将函数推广到数相等,我们需要减法。就像我们用 add1 实现加法一样,减法可以用 sub1 实现。但是,尽管 add1,add 和 iszero 函数在 Church 的书编码中非常简单,sub1 会显得略微复杂。sub1 将接收的数值函数作为参数,并且应用 n 次,但是其返回的函数却要 应用函数一次。当然,任意函数的逆函数不可用于反转一个应用程序。

实现 sub1 的函数分为两个部分:

  • 将给定的参数 x 与 true 成对。 true 标示了对 f 的应用应该被跳过
  • 将给定的函数 f 封包,以接收对值,以及当对值用含有 false 时应用 f 。必定返回一个包含 false 的对值,以确保 f 会在将来被应用。

wrap 函数将给定的 f 封包:
在这里插入图片描述

sub1 函数接收一个 n 并且返回一个新函数,新函数接收 f 和 x, 用 wrap 函数将 f 封包,并且将 x 与 true 对编码, 在 (wrap f) 和 ⟨true, x⟩ 上使用 n,并且抽出结果的第二部分 —— f 应用于 x (n - 1) 次。
在这里插入图片描述

有关编码的提示:对 0 的编码与对 false 的编码一致。因此,没有程序能够区分 0 与 false,编程者必须确保只有在布尔上下文中才使用 true 和 false。这与 C语言使用相同的比特值实现 0、false和null指针类似。

练习 4.6

证明 add1 1 =n 2

题解

add1 1 = (λn.λf.λx.f (n f x)) (λf.λx.f x)

nβ λf.λx.f ((λf.λx.f x) f x)

nβ λf.λx.f ((λx.f x) x)

nβ λf.λx.f ((λx.f x) x)

nβ λf.λx.f (f x) = 2

练习 4.7

证明 iszero 1 =n false

题解

iszero 1 = λn.n (λx.false) true (λf.λx.f x)

nβ (λf.λx.f x) (λx.false) true

nβ (λx.(λx.false) x) true

nβ (λx.false) true

nβ false

练习 4.8

证明 sub1 1 =n 0

题解

sub1 1 = (λn.λf.λx.snd (n (wrap f) ⟨true, x⟩)) (λf.λx.f x)

nβ λf.λx.snd ((λf.λx.f x) (wrap f) ⟨true, x⟩)

nβ λf.λx.snd (λx.(wrap f) x)⟨true, x⟩)

nβ λf.λx.snd ((wrap f) ⟨true, x⟩)

= λf.λx.snd (((λf.λp.⟨false, if (fst p) (snd p) (f (snd p))⟩) f) ⟨true, x⟩)

nβ λf.λx.snd ((λp.⟨false, if (fst p) (snd p) (f (snd p))⟩) ⟨true, x⟩)

nβ λf.λx.snd (⟨false, if (fst ⟨true, x⟩) (snd ⟨true, x⟩) (f (snd ⟨true, x⟩))⟩)

→→n λf.λx.snd (⟨false, if true (snd ⟨true, x⟩) (f (snd ⟨true, x⟩))⟩

→→n λf.λx.snd (⟨false, snd ⟨true, x⟩)⟩

→→n λf.λx.snd ⟨false, x⟩

→→n λf.λx.x

= 0

练习 4.9

用帮助我们实现 add 的方式定义 mult 。换句话说,实现 (mult n m) ,利用 n 本身应用函数 n 次的事实,应用 m 于 0 n 次 加法。(提示: (add m) 是什么类型的值?)

题解

mult ≐ λn.λm.λf.m (n f)

练习 4.10

Lambda演算没有提供错误信号的机制,如果 sub1应用于 0 之后,将会发生什么?当 iszero 应用于 true 后,将会发生什么?

题解
  • sub1 0 = (λn.λf.λx.snd (n (wrap f) ⟨true, x⟩)) (λf.λx.x)

    nβ λf.λx.snd ((λf.λx.x) (wrap f) ⟨true, x⟩)

    nβ λf.λx.snd ((λx.x) ⟨true, x⟩)

    nβ λf.λx.snd ⟨true, x⟩

    →→n λf.λx.x = 0

  • iszero true = (λn.n (λx.false) true) (λx.λy.x)

    nβ (λx.λy.x) (λx.false) true

    nβ λy.λx.false true

    nβ λx.false

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值