负暄琐话

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

囧囧ID:g9yuayon
[修改头像]
780539次访问,排名36好友9人,关注者11
g9yuayon的文章
原创 239 篇
翻译 4 篇
转载 48 篇
评论 790 篇
g9的公告
最近评论
alextooter:ff可是用的完全的自己内存管理。。

最近ff3非常好,值得试试看。
fferror:无比期待g9老大的model checking续集。
sprhawk:哈哈,太强了,最近刚听说有Erlang,了解一下。
看一下历史,比看语法有意思得多嘿嘿
lordchl:后面提示下不动点好了,跳得太大
lbaby:Do you mind if I jot down some notes on your chests ??


猛到无以复加
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes
文章分类
收藏
    相册
    旅游
    计算机科学
    Lambda the Ultimate
    软件开发
    Reddit编程专栏(RSS)
    正在读的书
    存档

    原创 翠花儿,上代码

    新一篇: 你和你的研究

    上篇帖子里聊到Sussman认为构造出健壮软件需要我们的系统支持continuation, 回溯,和生成-测试的方法。生成-测试最直观简单的方式是为系统提供多项结果。系统一个一个地测试这些结果,并接受符合要求的一个。Sussman举了一个例子:平方根函数通常返回正根,而抛弃那个负根。那按照生成-测试的方法,一个平方根函数应该将负根和正根一起返回,然后由系统决定到底哪个根更好。后来他进一步提到(第20页最后一段)可以返回正负根的AMB值。昨天写帖子写得头晕眼花,竟然忘记讨论这坨精彩的函数(编程意义上)。今天补上。我们可以看到一个简单(简单不等于浅显哈)的抽象,居然能实现众多美妙的功能。一个看似无意创造的玩具,竟然是有助于揭示构建辉煌软件大厦的秘密。
     
    AMB这个操作符历史久远。AI大牛,LISP的奠基人,John McCarthy在这篇1961年的论文里首次提出了模糊函数(ambiguous function)。我们一般把这个函数简写为AMB。似乎最近俺读的文章也好,书也好,都越来越年代久远。不过不怕打击喜欢追新的老大们:现在流行和将要流行的技术背后的理念都至少有20年的历史。比如这个AMB函数,虽然1961年就被提出,但知道1987年还有研究它的论文发表。互联网?Google一下Douglas Engelbart。面向对象?Google一下Simula和Alan Kay。垃圾收集?Google一下LISP。BPEL?Google一下Robin Milner。作为编程语言的XML? Google一下S-Expression。元编程?Google一下Metaobject Protocol和CLOS。这其实符合技术革新的规律:大学里新奇的编程手段差不多要20年到30年才被大众接受。新理念提出后,还得被无数学者验证,润色,完善;还需要无数工程师实现,优化,改进,推广。所以说呢,如果老大们不满足于赶潮而憧憬弄潮,慢下来,向后看,也许是不错的手段。跑题老,还是说这个AMB操作符。俺最早在SICP上读到关于AMB的讨论。SICP也算是一本奇书。大一的入门教材,问世20来年了,里面的内容仍然让人拍案叫绝。每年翻开这本书,都能学到一点新的东西。书的第三章已经开始详细讨论并发和stream。第四章详细讲述了梦幻般的meta-circularity,接着就是现在开始热门的lazy evaluation,和logic programming。而第五章干脆教我们搭建一个简单的寄存器机器。又跑题了。最近越来越像老人家,变得唠叨。通俗讲,amb接受0或多个参数,并不确定地返回其中一个参数。比如说,amb(1, 2)可能返回1,也可能返回2。如果amb没有参数,那它不返回任何值,并抛出异常。也就是说,amb()一定挂掉。同时,amb的参数可以是一个函数(对用C/C++语言的老大来说,就是一个函数指针),amb返回的值必须是不会抛出异常的参数。比如说,amb(amb, 1)必须返回1,因为amb()会抛出异常。同理,amb(1, amb)也必须返回1。显然,amb的实现不能是简单的检测每个参数。比如下面这段代码里的amb(false, true)必须返回true, 不然else里的amb()就会被调用,导致这段代码抛出异常。
    if amb(falsetrue
       
    return 1
    else
       
    return amb()
    end
    那这种不确定的函数到底有什么用呢?呵呵,用处大了。它正好简单地模拟了生成-测试:我们有一系列备选答案。我们把这些答案传给amb,他返回不会失败的那个。这不正好符合生成-测试的定义么?其实哪怕编程中这个函数也有妙用。比如说下面这道题(SICP4.3.2):

    Baker, Cooper, Fletcher, Miller, 和Smith住在一动5层公寓的不同楼层。Baker不在顶楼住。Cooper不在底楼住。Fletcher既不在顶楼也不在底楼。Miller住的楼层比Cooper住的高。Smith和Fletcher的楼层不相邻。Fletcher和Cooper的楼层不相邻。问每个人住的楼层。
    有了amb这个函数,我们可以这么解决这道题(为了方便大多数人,我把Scheme代码移植到Ruby代码了。调用amb()变成了amb.choose):
     
    看哈,每一行语句直接对应题目的条件。没有循环。没有递归。全靠amb这个看似简单的函数。运行的结果是:
     
    有Scheme运行环境的老大们可以运行下面的代码(在实现amb以后)。结果一样。
     
    第一次看到这段代码,我只觉得背后妖风阵阵。从来没有想到过,程序能写到这个地步。每一行语句居然和题目条件切合。比伪代码还为伪代码,但偏偏可以运行。那到底amb怎么实现?为什么俺要专门说这个函数呢?原因是这个函数的实现要用到continuation和回溯。当然不用continuation也能实现。比如用Java也行(友情提示:thread + 匿名类)。不过用continuation的方法最为简洁。Ruby代码不过10来行。所以我们先简介一下continuation。
     
    Continuation到底有多重要一直有争议。Matz在邮件组里说Ruby 2.0会去掉continuation, 因为没有”compelling use cases”,结果引来一场讨论。Avi Brant就力挺continuation,毕竟他的Seaside框架就是基于continuation技术的。对了,Avi在今年的ETech会议上做了报告,批评RoR方法落后。这里有会议笔记,非常有教育意义。简单说,continuation就是高级goto,好比C下面的setjmp/longjmp + Solaris下的getContext()。它允许程序记住某一点的所有状态,然后在其它时刻回到那一点,继续执行。用Ruby举例(Ruby的callcc和Scheme的用法没有本质区别):Ruby的函数Kernel#callcc生成一个Continuation对象,并把这个
     
     
    知道了Continuation和回溯的概念,实现Amb也就容易了。因为是Ruby,我用了一个类来封装变量backtrack_points。这个实现的本质是深度优先搜索。每一步的状态用Continuation保存起来,回溯时使用。这本写得很好的Scheme入门书上也有amb的实现。Ruby Quiz提供了类似的代码,是从同一本书的Scheme代码直接移植的。不过Scheme不支持return, 所以它的实现用了两个call/cc。外层的用于模拟return (所谓的escaping continuation)。所以移植的代码不是那么容易理解。在Ruby里用了return语句后,代码要干净清晰得多:

     
    困。。。代码的解释改天继续。也许这段代码很直观不需要解释呢?哪位老大读到了这里,说说看?先谢谢了。
     

    发表于 @ 2007年04月23日 14:00:00|评论(loading...)|编辑

    旧一篇: 推荐一篇文章:构造健壮系统

    评论

    #googol 发表于2007-04-24 14:30:55  IP: 10.193.48.*
    觉得对amb的描述不准确,应该是:返回值不能使之后的代码抛异常。

    也就是说,amb(amb,1)()时,amb(amb,1)必须返回1。而只有amb(amb,1)时,返回amb也无所谓,只要之后没有调用过amb()就行。

    不知道理解的对不对。

    另,不是很懂amb.choose if p这个语法,我不会ruby……

    再另,老大,你抓图把鼠标都抓进去了,太牛了,怎么抓的?
    #pi1ot 发表于2007-04-24 14:59:31  IP: 61.135.152.*
    之后的代码?之后多久?50行?进程结束?
    #fishhead_yutou 发表于2007-04-24 15:09:40  IP: 218.57.113.*
    俺菜,ruby的语法都看不懂。汗
    #googol 发表于2007-04-24 15:10:31  IP: 10.193.48.*
    另外,如果amb(amb, amb)的话,会返回什么呢?还是直接在amb里抛异常?
    #g9yuayon 发表于2007-04-24 21:31:48  IP: 199.246.40.*
    看来是没有说清楚。解释一下哈:
    amb管不了其它代码。它只能保证它自己不会挂掉,所以不能说“它的返回值保证以后的代码不抛出异常”。比如下面的例子就会抛出异常。
    if amb(false, true)
    return 1
    else
    throw "error"
    end

    另外,amb本身是个函数。同时我们假设我们的语言支持高端函数(或者函数指针),这样我们能把amb当成数据传递。也就是说,amb()表示调用这个函数, 而amb表示这个函数本身。这样的话,amb(amb, 1)就表示调用函数amb,传给它两个参数,其中一个是amb这个函数。amb自己在返回参数前会把参数当表达式执行,相当于说当它返回值的时候,它会这么做(假设返回哦值叫arg):
    if arg is callable:
    return arg.call()
    else:
    return arg

    关于amb.choose:实现amb这个函数需要用到全局变量。我不喜欢为了一个函数增加全局变量,所以创造了一个类叫Amb,用来包装amb()的逻辑。那Amb#choose实际上就等同与amb这个函数了。

    我用的HyperSnap。它支持截图时抓取鼠标。前短时间需要抓取鼠标来展示软件某些功能,后来忘记关了。
    #g9yuayon 发表于2007-04-24 21:33:02  IP: 199.246.40.*
    pi1ot: 之后多久都无所谓,反正amb自身不挂掉就行了。
    #hawk_e2e 发表于2007-04-25 00:20:45  IP: 58.63.91.*
    我不懂RUBY。
    不过想问一下老大,RUBY跟JAVA比性能差多少,还有能否支持接口?
    #albertlee 发表于2007-04-25 16:30:30  IP: 221.218.185.*
    用Haskell写了一个, List Comperhension 就是一种内涵的amb机制吧

    module Main where

    import IO
    import List

    distinct :: Eq a => [a] -> Bool
    distinct l = if length l == (length $ nub l) then True else False

    dwelling = [(baker, cooper, fletcher, miller, smith) |
    baker <- [1..5],
    cooper <- [1..5],
    fletcher <- [1..5],
    miller <- [1..5],
    smith <- [1..5],
    distinct [baker, cooper, fletcher, miller, smith],
    baker /= 5,
    cooper /= 1,
    fletcher /= 5,
    fletcher /=1,
    miller > cooper,
    abs (smith -fletcher) /= 1,
    abs (fletcher - cooper) /= 1]

    main = print dwelling


    ---
    运行结果:
    albert@albert-laptop:~/progs/haskell$ ./amb
    [(3,2,4,5,1)]

    #albertlee 发表于2007-04-25 16:38:04  IP: 221.218.185.*
    代码贴乱了,看原文吧:
    http://www.kamang.net/node/26
    #g9yuayon 发表于2007-04-25 23:31:22  IP: 199.246.40.*
    Albert的解法很安逸啊。不过用list comprehension和用amb还是有点不同的吧:<- generator会尝试所有的组合,生成所有符合条件的答案。而用amb的话,只会生成第一个符合条件的答案。这道题的答案就一组,所以区别不明显。Haskell也提供callCC和Cond Monad,可以用来实现amb哈。:-)
    #g9yuayon 发表于2007-04-25 23:35:39  IP: 199.246.40.*
    hawk老大,离开应用谈性能(再说什么性能?)没有多大意义哈。如果说是网上流行的那些比较语言的基准测试,Java还是快不少就是了。至于接口,Ruby里用不着这个概念。需要什么方法,实现就行了。
    发表评论  


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