现在的位置: 首页 > 综合 > 正文

奇妙的邱奇数

2013年12月12日 ⁄ 综合 ⁄ 共 1861字 ⁄ 字号 评论关闭

每个人都在描述自己眼中的世界。

 对大家来说自然数真的是再“自然”不过了,我们可以它用来计数,可以用它来做加减乘除运算,一些都是那么自然。自然数是数据,而加减乘除这些处理数据的就被叫做过程,这是大家都公认的,然而数据和过程的界限真的这么清晰吗?一天,一个叫阿隆佐·邱奇的人发明了一种新的计数方式:用lambda算子来描述自然数。这种计数方式被后人称作邱奇数(Church
encoding)
,具体来说就是用过程来描述数据。抛开晦涩的形式定义,我们用代码来一点一点引出邱奇数的定义,由于复杂的lambda表达式难以阅读,因此下面的示例都用的Python代码。

伽利略说过:“给我一个支点,我就能举起地球”。我们只要一个0和一个自增操作就可以表示所有的自然数了,1就是0进行一次自增操作,2就是1进行一次自增操作.....
犹如“鸡生蛋,蛋生鸡,鸡鸡蛋蛋无穷尽也”。同时我们注意到2其实也是0进行两次自增操作

def zero(inc, base):
    return base
def one(inc, base):
    return inc(base)
def two(inc, base):
    return inc(inc(base))

其中的zero, one, two就是邱奇数。聪明的你可能已经注意到了,其实邱奇数就是在一个函数g(f,x),自然数n的邱奇数映射就是在x上作用n次f也即是n->fn(x)这样手工来一个一个静态来定义邱奇数太麻烦了,我们需要一个自增操作,那邱奇数的自增操作是什么呢?先看代码

def succ(n):      
    def res(inc, base):
        return inc(n(inc, base))
    return res

由于本质上邱奇数是一个函数,因此我们先定义了一个函数res作为succ的返回值。其中n(inc, base)的作用是得到邱奇数n的反映射n'(比如two->2) ,然后再在n'上叠加inc调用,最后我们再把这个函数返回,这样就完成了一次自增的操作。看看效果如何

def inc(n):
    return n + 1
def _three(inc, base):
    return inc(inc(inc(base)))

three = succ(two)
#equal(_three, three)
print two(inc, 0)    # 2 
print three(inc, 0)  # 3

如果有一个equal函数来验证的话当然更好(目前我还没有找到验证两个函数相等的方法),在这里我采用了直接带入参数来验证结果。

加法的代码也非常简单

def add(m, n): 
    return n(succ, m)

我们再回忆一下前面的内容,邱奇数n(inc, base)->n' 的本质就是对base进行n'次inc操作。如果我们的自然数也可以接收参数,那计算2+3就可以表示成这样2(++, 3), 就是用3做base, 进行两次自增,是不是就得到了加法的效果?用这样的思想,我们引出乘法的操作。

小学的时候我们就学了m*n = m + m + m + ..... ,抽象一下:m*n就是在0的基础上进行n次加m操作,结合前面的邱奇数定义我们可以直接写出乘法的操作 

def mult(m, n):
    return n(adder, zero)

其中的adder就是加m操作,那怎么表示这个加m操作呢? 在学求偏导数数的时候,我们一般是把一个变量当作自变量,其他的作为常量。这里我们用了同样的方法,把m+n中的m确定

def adder(x):
      return add(m, x)

这样我们就得到了一个函数,一个进行加m操作的函数,完整的乘法是这样的

def mult(m, n): 
    def adder(x):
        return add(m, x)
    return n(adder, zero)

聪明的你是否已经想到了幂乘的算法了呢?这里我把代码贴出来,看是否和你想的一样

def exp(m, n): 
    def multer(x):
        return mult(m, x)
    return n(multer, one)

至此我们已经完成了邱奇数的自增,加法和乘法操作,至于减法和除法操作,有兴趣的同学可以去wiki上看看,这里就不多说了。

在函数是第一公民的语言里,我们有了更广阔的表达能力,数据中蕴含着操作,过程中又蕴含着数据,是不是很类似面向对象呢,sicp的第二章中就用函数描述了一个对象系统。语言也在影响着我们的思考方式,c语言的指针让我们对内存有了灵活的操作,在有垃圾回收的语言中我们可以更专注于业务逻辑,lisp更是可以把自己的代码当作基本的数据来分析,以至于很容易用lisp来写一个自己的解释器.....  路漫漫其修远兮,吾将上下而求索。


抱歉!评论已关闭.