likes
comments
collection
share

函数式编程的数学基础(三)邱奇数的比较,分支逻辑

作者站长头像
站长
· 阅读数 57

我们已经有了邱奇数的加、减和乘法。

但是现在lambda定义的邱奇数看上去无法互相比较,我们这里就考虑一下如何实现邱奇数的比较。

TRUE和FALSE

要想实现比较运算,我们首先要再lambda体系中定义TRUE和FALSE。

因为lambda演算中只有函数,所以我们思考一下,TRUE和FALSE应该是什么样的函数?

考虑到,我们一般使用布尔类型都是用于分支逻辑,所以我们把TRUE和FALSE设计成类似if和else的结构。

我们让TRUE和FALSE以柯里化的形式接受两个值,然后TRUE返回第一个值,FALSE返回第二个值:

TRUE=λx.λy.xFALSE=λx.λy.yTRUE = \lambda x.\lambda y.x \\ FALSE = \lambda x.\lambda y.yTRUE=λx.λy.xFALSE=λx.λy.y

这样我们就可以直接把这种布尔类型的函数当作if使用。我们调用某一布尔型函数:

(b x y)(b\ x\ y)(b x y)

这里等价于

if(b)
    return x;
else
    return y;

从数学的角度,这个形式完全没有问题,但是如果我们真正要落到可执行的程序代码,有时我们希望x或y不要进行计算,这时我们就还要稍微做一些处理,我们留待后文讨论。

判断是否是0

有了TRUE和FALSE,我们来考虑如何实现邱奇数的比较,首先我们来考虑一个基本的问题,判断一个邱奇数是否为0。

我们先来复习一下邱奇数:

ZERO=λf.λx.xONE=λf.λx.(f x)TWO=λf.λx.(f (f x))...... ZERO = \lambda f.\lambda x.x \\ ONE = \lambda f.\lambda x.(f\ x) \\ TWO = \lambda f.\lambda x.(f\ (f\ x)) \\ ......ZERO=λf.λx.xONE=λf.λx.(f x)TWO=λf.λx.(f (f x))......

我们看到,除了0以外,其它邱奇数生成的lambda函数都至少会调用一次函数f。

于是我们可以构造一个把任何值变成FALSE的f,和一个值为TRUE的x。

isZero=λn.(n (λa.FALSE) TRUE)isZero = \lambda n.(n\ (\lambda a.FALSE)\ TRUE)isZero=λn.(n (λa.FALSE) TRUE)

这样我们就有了第一个比较运算。

大于等于和小于等于

这里我们要用到上一篇中的减法。我们来考虑一下,当我们用一个较小的数减掉一个较大的数,会发生什么。

根据predpredpred的实现方案,我们发现,这样的减法并不会产生负数,而是会固定得到0。

结合我们上一小节实现的 isZero,我们就可以得到大于等于和小于等于

lessOrEqual=λm.λn.(isZero (minus m n))greaterOrEqual=λm.λn.(isZero (minus n m)) lessOrEqual = \lambda m.\lambda n.(isZero\ (minus\ m\ n))\\ greaterOrEqual = \lambda m.\lambda n.(isZero\ (minus\ n\ m))lessOrEqual=λm.λn.(isZero (minus m n))greaterOrEqual=λm.λn.(isZero (minus n m))

逻辑运算:与、或、非

目前为止,我们仅仅得到了判断0、大于等于和小于等于两种比较运算。很容易想到,如果我们的布尔类型能进行布尔运算,我们就能够实现其它比较运算了。

我们先考虑与运算。其大致形态应该是:

and=λx.λy. ... and = \lambda x.\lambda y.\ ...and=λx.λy. ...

我们看下and运算的真值表:

xyx && y
TRUETRUETRUE
TRUEFALSEFALSE
FALSETRUEFALSE
FALSEFALSEFALSE

不难发现,当x为TRUE时,其结果与y一致,当x为FALSE时,其结果必然为FALSE。

所以我们可以根据这个规律写出and

and=λx.λy.(x y FALSE) and = \lambda x.\lambda y.(x\ y\ FALSE)and=λx.λy.(x y FALSE)

同理我们可以写出or

or=λx.λy.(x TRUE y) or = \lambda x.\lambda y.(x\ TRUE\ y)or=λx.λy.(x TRUE y)

非运算则非常简单:

not=λx.(xFALSE TRUE) not = \lambda x.(x FALSE\ TRUE)not=λx.(xFALSE TRUE)

相等,大于,小于

有了逻辑运算,我们可以从大于等于和小于等于得到等于

equal=λm.λn.(and (lessOrEqual m n) (greaterOrEqual m n))equal = \lambda m.\lambda n.(and\ (lessOrEqual\ m\ n)\ (greaterOrEqual\ m\ n))equal=λm.λn.(and (lessOrEqual m n) (greaterOrEqual m n))

结合非运算,可以得到不等于:

notEqual=λm.λn.(not (equal m n))notEqual = \lambda m.\lambda n.(not\ (equal\ m\ n))notEqual=λm.λn.(not (equal m n))

有了不等于,再从大于等于和小于等于中得到大于和小于:

less=λm.λn.(and (lessOrEqual m n) (notEqual m n))greater=λm.λn.(and (greaterOrEqual m n) (notEqual m n))less = \lambda m.\lambda n.(and\ (lessOrEqual\ m\ n)\ (notEqual\ m\ n))\\ greater = \lambda m.\lambda n.(and\ (greaterOrEqual\ m\ n)\ (notEqual\ m\ n))less=λm.λn.(and (lessOrEqual m n) (notEqual m n))greater=λm.λn.(and (greaterOrEqual m n) (notEqual m n))

结语

到此,我们实现了邱奇数的比较运算,还获得了分支逻辑的能力,分支是达成图灵完备的重要条件之一,接下来我们只需要再获得循环的能力,就可以论证邱奇数的图灵完备性(注:事实上,历史中邱奇数的图灵完备性论证比结构化程序设计提出要早,所以它使用的是另外的方法)。

转载自:https://juejin.cn/post/7250398488714248249
评论
请登录