负暄琐话

我的email: rot47('649@ 6(hF+`hd"w=92vhG{>}G3"@l M >:>6?4@56 \F')

囧囧ID:g9yuayon
901710次访问,排名34好友44人,关注者44
姓名:g9yuayon
前世:夜郎国厚脸皮神棍
魅力指数:0
名气:1
宠物:一只从来不对生人叫的看门狗
g9yuayon的文章
原创 244 篇
翻译 4 篇
转载 49 篇
评论 902 篇
g9的公告
最近评论
ErikLiu:看了这样的文章, 我会流泪.

如果说, 三十年前, 我流泪, 不奇怪,

30多岁的我, 流泪了
ErikLiu:看了这样的文章, 我会流泪.

如果说, 三十年前, 我流泪, 不奇怪,

30多岁的我, 流泪了
devil_hua:孤陋寡闻了。。。汗啊,看来知识缺得还真不是一丁点,哥们强
devil_hua:孤陋寡闻了。。。汗啊,看来知识缺得还真不是一丁点,哥们强
f891379133:好tuo,
文章分类
收藏
    相册
    旅游
    计算机科学
    Lambda the Ultimate
    软件开发
    Reddit编程专栏(RSS)
    正在读的书
    存档
    订阅我的博客
    XML聚合  FeedSky

    翻译 lambda算子3:阿隆佐.丘齐(Alonzo Church)的天才收藏

    新一篇: 书签(2006-08-13) | 旧一篇: lambda算子3:阿隆佐.丘齐(Alonzo Church)的天才

    lambda算子3

    阿隆佐.丘齐(Alonzo Church)的天才:Lambda算子里的数

    前面建立了lambda运算的基本规则,就可以用lambda算子做点有意思的东西了。开始前为方便计,我们先来点语法糖花差花差,用来命名函数。这些语法糖可以让复杂的公式好写一点。

    我们用"let" 来引入一个“全局”函数(也就是说,我们用这个函数时,不用在每个表达式里定义一次):
    let squer = lambda x. x^2

    这个式子申明了一个叫"square"的函数,定义为 lamdba x. x^2。如果我们有一个表达式 "square 4",上面的"let"意味着这个表达式和下面这个表达式一样:
    (lambda square. square 4)(lambda x. x^2)。这个"let"是从Common Lisp或者Scheme里借来的。Lambda算子里可没有这个东西。数学家推崇“如无必要,毋增实体”。这些关键字不入他们的法眼。不过对写惯了程序的我们来说,这些句法糖就可爱多了。

    我们的例子里会用到数字和算术操作符。不过记住lambda算子里根本没有数字。我们只有函数!所以我们需要发明用函数来创造数字的方法。幸好Alonzo Church是个天才。他既然发明了lambda算子,用lambda算子表征数字自然不在话下。他搞出的用于数字的函数自然就叫做丘齐数(Church Numerals)。

    丘齐数里,所有的数字都是两个参数的函数:

    1. 零是 lambda s z . z
    2. 一是 lambda s z . s z
    3. 二是 lambda s z . s (s z)
    4. 对任意一个数"n",它的丘齐数都是一个函数。这个函数把它的第一个参数应用到第二个参数上n次。用流行的写法,就是lambda s z . s sn z。 绕口啊绕口。做形式化的东东不幸之处就是成天和绕口令打交道。解脱这道呢?当然就是牢记牛人费因曼在Connection Machine工作时的学习方法:问最简单的问题。“给我最简单的例子”。“怎么才能验证这是正确的?”。
      比如说零(lambda s z . z)吧,第一个参数是s, 应用零次就是没有,所以函数体就是孤零零的"z"。那数字一呢?当让就是把第一个参数,s,应用到z上一次,所以函数体就变成了"s z"。

    理解这个定义的方法之一时把"z"看作丘齐数里零的名字,而把"s"看后继函数(successor function)的名字。“后继函数”其实很简单,C/C++里的++是也。所以呢,零就是一个返回"0"这个值的函数;一就是把后继函数应用到零上一次的函数;二就是把后继函数应用到一上一次或者说零上两次的函数。0++ 得到 1, 1++ 等价与(0++)++,而1++得到2.现在把0换成z,把++换成s, 一切就清楚了。


    现在--看好了。如果我们想做加法,x+y,我们需要一个带4个参数的函数。两个参数代表相加的两个数字,以及为得到结果而需要的"s"和"z"。

    let add = lambda s z x y . x s (y s z)

    看着好像有点不知所云。不过我们可以用Curry这个利器,分开"s" "z"和x, y。首先,Curry后得到的函数带两个参数,x和y(这个好比add(x, y),符合我们对加号的理解)。其次,我们需要正规化x和y需要的s和z,让x和y共享相同的零和后继函数的绑定:

    let add = lambda x y. (lambda s z . (x s (y s z)))

    仔细观察一下,上面的式子无非是说,要把x和y相加,我们先用"s"和"z"创建丘齐数"y",然后在把"x"应用到y上。应用时需要的"s"和"z"是"y"里的"s"和"z"。也就是说,我们的到的结果是一个函数,这个函数把自己加到另一个函数上。还是用例子来说明问题。比如说2+3:

    add (lambda s z. s (s z)) (lambda s z . s (s (s z))) news newz

    为了让演算变得稍微容易一点,我们先对2和3来个Alpha转换。让2用s2和z2,而3用s3和z3:

    add (lambda s2 z2 . s2 (s2 z2)) (lambda s3 z3 . s3 (s3 (s3 z3)))

    现在我们可以把"add"替换成它的定义了:

    (lambda x y .(lambda s z. (x s y (s z)))) (lambda s2 z2 . s2 (s2 z2)) (lambda s3 z3 . s3 (s3 (s3 z3))) 

    现在可以对"add"用beta变换了(温馨提示:也就是把形参x和y换成对应的实参):

    lambda s z . (lambda s2 z2 . s2 (s2 z2)) s (lambda s3 z3 . s3 (s3 (s3 z3)) s z)


    然后我们可以对3这个丘齐数做beta转换。这步操作其实是“正规化”3:把3的定义里的后继函数和零函数(还记得零是个函数吧?)替换成add的参数列表里的后继函数和零函数:

    lambda s z . (lambda s2 z2 . s2 (s2 z2)) s (s (s (s z)))

    嗯,有点眉目了。现在是真正漂亮的地方了。再来次对2的Beta变换。看看我们准备做什么:2是个带两个参数的函数:一个参数是后继函数,另一个是零函数。要把2加到3上,我们只需要用到"add"这个函数的后继函数。也就是说,我们把计算了3后的结果当成零函数的值!

    lambda s z . s (s (s (s (s z)))

    而这个式子,正是丘齐数5!

    丘齐数酷的地方是它抛弃了传统整数的概念,用函数取而代之。它把每个数对应为一个函数。而数数(counting)这个操作被对应为应用某个函数(在这里是后继函数)的次数。当然了,上面的介绍非常简单。对丘齐数感兴趣的,可以看这篇文章

    丘齐数对编程有什么用嗫?俺还真不知道。但丘齐数(进而到丘齐编码)确实一系列基础理论中有重要应用,比如说有类型的lambda算子。不过这点重要吗?不重要吗?重要吗?不重要吗?研究研究嘛。

    发表于 @ 2006年08月14日 14:47:00|评论(loading...)|编辑

    新一篇: 书签(2006-08-13) | 旧一篇: lambda算子3:阿隆佐.丘齐(Alonzo Church)的天才

    评论

    #baikaishiuc 发表于2008-03-08 22:26:34  IP: 125.71.4.*
    你多发了一次。
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © g9