函数式编程的数学基础(二)邱奇对,邱奇数减法
邱奇数的加法和乘法并不难理解。它们仅仅是在函数调用的基础上进行叠加。那么,是否有方法实现邱奇数的减法呢?
假设给我们一个邱奇数n,我们几乎没办法知道它的内部结构,我们能够对它做的操作仅有“调用”。
那么,倘若邱奇数可以实现减法,那么奥秘一定在于给邱奇数传入了特殊的参数。
邱奇数的减法实现较为繁琐,而且有多种思路。我们这里挑选其中较为容易理解的一种来讲解。
要实现邱奇数减法,实现一个减一运算是至关重要的。那么如何实现减一呢?
我们设想,假如我们传给邱奇数的函数f,能够接受和存储上一次调用的结果,即实现这样一个函数:
[a, b] => [b, b + 1]
那么,把它传给邱奇数调用n次之后,就可以得到n-1的结果了。
但是,在我们面前还有待解决的问题:lambda演算中并没有数组这样的数据结构,哪怕我们只需要存储2个邱奇数。那么我们就要考虑一下,如何实现这样的一种数据结构了。
邱奇对
存储2个函数(经典lambda演算中函数既是数据,又是操作)的数据结构被称作邱奇对。
我们首先考虑,假设有这么一种邱奇对,我们该如何使用它。
因为lambda演算中一切数据没有除了调用以外的方法,那么,邱奇对大体的使用方法可能,邱奇对p接受一个函数s,s能够接收到p中存储的数据x和y
所以邱奇对应该是一个这样形状的一个函数:
所以构造邱奇对的函数应该是这样的:
为了方便使用,我们可以实现一些常见的操作邱奇对的方法,比如取第一个first和取第二个second:
实际使用的时候,如果已经比较熟练,也可以不用first、second这些名称,直接写其内容。有了邱奇对,我们可以考虑实现减法了。
邱奇数的前一个数(减一运算)
"前一个"的英文是predecessor,我们可以利用前面的邱奇对实现这一函数。首先我们实现前文所讲的函数f,即:
const f = [a, b] => [b, b + 1]
这个函数的lambda版需要邱奇对和加一运算。加一运算的英文是successor,我们把函数名简写为succ。succ的实现很简单简单得多,我们这里不展开讲解了。
接下来我们实现这个f。
有了这个f,我们只需要把它对邱奇对<0,1>执行n次,就可以得到n - 1的值。
其中,ZEROZEROZERO和ONEONEONE的定义可以看上一篇。
有了succsuccsucc函数,我们可以轻易实现邱奇数减法。
其它思路
除了利用邱奇对,pred函数还有其它思路,它形式上更简洁,但推导过程更具有技巧性,此处我们仅仅给出其形式,供大家自行研究:
结语
到此,我们已经在lambda体系中实现了一个基础数据结构邱奇对和邱奇数的减法,四则运算中我们仅剩下除法运算还没有实现。
在接下来的几篇中,我们将会继续补全邱奇数的基本运算和一些编程所需的结构。
转载自:https://juejin.cn/post/7249664547219701815