Archive for 六月, 2009

你选择站在时间的对立面

Posted on 六月 25th, 2009 in 杂碎 | No Comments »

一直回避谈论这个国家里发生的事情。在现实中谈论,身边的人不一定了解,交流容易冲突;在网络上谈论,大家言行一致,不免会带上一点“政治正确性”,个人见解也就无从轻重。另外一个原因就是讨厌政治,不想介入任何一个派别,有派别就有无聊的争端,古来如此。

于是一直以来都是不说话,而以娱乐的心态围观这些事情,一笑了之。我相信对人对组织最大的打击就是娱乐,或者说“滑稽”,“荒唐”,如果一个人或组织可以被拿来取乐,那么他做的又会是怎样的事情?是小丑,就一定要极尽扭捏之态,古来也是如此。好吧,娱乐有底限,到底限就笑不出来了。只会觉得恶心。

以色列人有句话“上帝让他灭亡,必先让他疯狂”。大秦、满清和苏俄曾经都是如何的不可一世,他们都失败了。而且是一触即溃的失败。

不要选择技术为敌。时间站在技术背后。技术不朽。

ps:访问swdpress.cn时您浏览器的进度条会比较慢,那是google friend connect被封的缘故。

update:google friend connect已经恢复。 09.6.25 21:44

还是数学

Posted on 六月 20th, 2009 in 笔记 | 17 Comments »

前两个月看了本日本人写的《给讨厌数学的人》,写了篇猥琐至极的关于数学(很欣慰,还不如那日本人写的猥琐),把本人的无知暴露无遗。当时小,不懂事。阿门。

之后又继续读了些《逻辑的引擎》《数学史》《数学:确定性的丧失》《从一到无穷大》之类的科普书,呃,对数学是什么也不敢说了。一个过于复杂的系统绝不是一言两语能说清的。唯一能说清的貌似就是,”数学有个啥用?”之类问题的回答貌似永远不会让提问者满意。

这几本书的角度各不相同,倒都是不错的书。

在几本书里,《逻辑的引擎》应该是学CS的同学最亲切的书了。从莱布尼茨之梦开始展开,布尔,康托尔,希尔伯特,哥德尔,图灵的故事一线延续,直到最终计算机的发明,也涉及了点人工智能。俨然一部数理逻辑历史上的人物志。对符号逻辑,形式系统的诞生过程说的十分清楚,也规避开了罗素那堆相对比较学术的东西,读起来还是比较轻松的(我相信看这本书的时候的确搞明白了哥德尔的那个不完备理论,不过现在貌似忘记了 = =)。整本书里都有一种乐观情绪,计算机到最后还是发明了嘛,超越了莱布尼茨的设想了嘛。不过后来阅读其他书籍的时候发现这本书的感情色彩貌似还是比较浓的,尤其是对直觉主义可以是极尽挖苦之能事。呵,搞学术的人们。

图书馆里有一种人,他们用书架上的书放到桌子上占座。然后某天ssword同学就无耻地把别人用来占座的书给借了出来。挺薄的书,封面上印了个立方体。从古巴比伦古中国的纯实用数学到古希腊的理论化,再从古希腊到牛顿和莱布尼奇对微积分的发明。写的中规中矩,评论也比较少,作者的个人情感也比较少。印象中比较深刻的就是古希腊“劳动都由奴隶做,市民中的一类人为了打发时间,于是钻研几何,他们被称作智者”—-我想这句话已经把理论数学的起源及意义解释的足够清楚了。希腊人认为可以使用几何来描述一切,数学就是几何。到后来中世纪,欧洲的数学停滞了,征服希腊的阿拉伯人倒是深得真传(先不谈“阿拉伯数字”,“代数”这个词就是algbre花剌子模的名字的一个音译)。到后来欧洲人反向阿拉伯人学习数学,之后产生了代数,产生了符号,产生了解析几何,产生了微积分,数学的发展在这本书里是一步一步向前,一步一步完善的过程。可惜的就是关于二十世纪数学的内容比较少。不过这本书里牛顿人品正如圣人一般,描述貌似与《逻辑的引擎》中正好相反,咳,搞学术的人们是分派别的嘛。

《数学:确定性的丧失》应该是最悲观的书了,其中前三章古代数学的内容里还是相当好看,数学,严谨,先验,上帝的语言,多好!古希腊人认为数学就是几何,几何就是对真实世界的反应。所以在古希腊的数学里,数字只是自然中存在的表示,像无理数,负数,之类都统统归避了开。不过后来的人们发现了欧几里德几何的缺陷,并不加思考地在数学里引入了负数,无理数,复数,虚数,四元数之类自然界中并不存在的数来发展了代数。这下好了,之后这本书的基调就变成了“误入歧途了!”。“代数就像一棵大树,枝繁叶茂却没有根。”数学的发展一步步与理性脱离,谁觉得怎么好使就怎么上,却不动脑子想想逻辑的基础。微积分的发明也是一个例子,牛顿和莱布尼茨都未能提供一个好的基础性解释,许多悖论也因而产生。无穷究竟该如何解释?谁也说不清。再往后人们觉得这样不合适啊,于是就重建数学的基础,后来重建基础的人们分裂了,逻辑主义,形式主义,直觉主义,集合公理主义,四个派谁也讲不清楚,而且谁也不服谁,于是各骂各的傻逼,各走各自的路。倒是应那句“所谓学术的发展,就是一个互骂傻逼的过程”。再往后就是哥德尔的不完备定理,证明了数学的局限性。作者在这里貌似有点偏袒直觉主义,表示数学这一学科在过去搞的形式太多,数学家们沉溺于自制的世界里,倒把数学本来的样子给忘了,导致数学成为少数人的游戏,有被边缘化的危险。其实倒不是太苟同作者的观点,后面的某章里提到某些数学的“无用”时有引用“谢天谢地,数论毫无用处”(貌似pascal说的?),呃,谢天谢地,数论可以用在密码学里。不过说到边缘化,如今的哪个学科不是如此呢?资本主义的社会还是功利,什么收益最快什么最牛逼。这点上我貌似要比作者乐观?

《从一到无穷大》貌似是最轻松的书了,看题目一开始还以为讲数学的来,原来对物理,数学,生物都有涉及。唉,要是高中时候看到这本书,高考时候没准能多考几十分呢。看这本书里最大的收获倒是对空间的理解,当时看《时间简史》的时候就是这儿不明白,绝对值得一看。再就是学到了一个词“人工数”,才知道“自然数”是个相对于“人工数”的词。

ps:有点讽刺,ssword同学的高数挂科在即。所谓叶公好龙即是如此吧…如今唯有坚定对春哥的信仰!阿门!

Fineday

Posted on 六月 14th, 2009 in 备忘 | 8 Comments »

学习haskell一段时间了,关于monad等等东西仍停留在理论上的理解而不了解其应用,练下手总是好的。于是参考这个有名的《Write Yourself a Scheme in 48 Hours》和parsec的手册,实现了个简单的语言。只是简单的递归解析语法树,也没有中间编译,也没有垃圾收集,实现起来还是比较简单的。某天天气不错,晴天,就叫它Fineday。

Fineday的语法比较接近javascript(其实一开始是打算搞成basic-style的,可是不会写bnf…囧),有基本的控制流程if,while,for,有匿名函数,有闭包,有数组,有hash—当然,是忽略了许许多多细节的实现,例如没有求数组length的函数,只有puts而没有gets,没有Int类型(开始的时候为了方便一切都是double),没有像样子的错误提示…呵,but it runs.

像下面这段可以算是一个猥琐的oo实现了:

function makeCounter(init){
    var this={
        'n':init,
        'add':function(n){
            this['n']=this['n']+n;
            return this['n'];
        }
    };
    return this;
}
var counter=makeCounter(1);
puts((counter['add'])(2)); --3
puts(counter['add'](3));   --6

前几天又翻了下姐姐送的那本《the ruby way》的序,matz谈及ruby语言的设计时提到了“道”,以及编写ruby时的信条:语言应该为人类服务,而不是相反。于是认识到,语言的设计绝非信手拈来的活计,设计中有太多需要斟酌的地方,有太多需要用心思考的地方。我等玩代码的,还是差的太远了。

项目地址:http://code.google.com/p/fineday/
呵,空白的,懒得再写字了。可以用svn获得源代码及编译的exe文件。

Haskell:可变状态的命令式语言

Posted on 六月 13th, 2009 in 翻译 | 4 Comments »

作者:Neil
翻译:ssword
原文:http://neilbartlett.name/blog/2007/04/11/haskell-an-imperative-language-with-mutable-state/

Haskell是一门惰性的纯函数式语言,也就意味着其中没有可变的变量。呃,有,没有?看下这个Factorial的haskell实现吧:

fact n = runST (do
    r < - newSTRef 1
    for (1,n) (\x -> do
       val < - readSTRef r
       writeSTRef r (val * x))
    readSTRef r)

嗯,我可没说这样写好。实际上,这样写很糟糕,一行纯函数式代码就可以漂亮的搞定同样的工作。不过请注意下这代码与命令式语言是如何的相像,如对“可变变量”r的破坏性更新。再贴一下,与同等的C代码做个对比:

 
fact n = runST (do               | int fact(int n) {
     r < - newSTRef 1             |    int r = 1;
                                 |    int i;
     for (1,n) (\x -> do         |    for(i=1;i< =n;i++) {
         val <- readSTRef r      |
         writeSTRef r (val * x)) |       r = r * i;
                                 |    }
     readSTRef r)                |    return r;
                                 | }

瞧,你几乎可以把C的代码一对一地翻译成haskell。不过得承认,haskell的语法要猥琐些。

这一切是如何做到的呢?答案就是ST monad,有了它就可以写出有内部状态更新而对外仍保持纯粹的算法。runST函数是亮点,它创建了个初始的空状态,然后执行一系列的状态转换,到最后再销毁它。fact依然是Int->Int的纯函数,依然保留了引用透明。

另一个亮点是那个“for”,看起来跟个关键字一般,不过它本质就是一普通函数,定义如下:

for :: (Int,Int) -> (Int -> ST s ()) -> ST s ()
for (i,j) k = sequence_ (map k [i..j])

同理,我们也可以定义出foreach,if,while等等。有haskell这般强大的表达力,没必要再将控制流的操作定义为语言的关键字;我们甚至可以根据自己的需求来发明新的控制流程。

不过你看出来了没?没人会正二八经地像上面那样实现factorial。而且,我们真的希望如这般曲解haskell,以取悦从C过来的老程序员么?

是的,问题就在这里。有这项技巧,是为那些已知难以使用函数式风格或递归搞定的算法提供的折衷。同样,很多算法需要用到数组—–有限的内存和固定的访问时间—–使其更易于处理。在ST monad中实现数组很容易,但在传统的纯函数式代码中就要困难多了。(UPDATE:Cale说,纯代码中实现不可变的数组还是很容易的,只有可变的数组实现其来才困难)。

恩,ST monad和STRef表示了外部不可见的局部状态,那么全局的可变状态呢?我们可以用IO monad和IORef做到。当然,在用IO的时候就没有像runST那样回到纯代码的函数了[1]。

对我,这引发的思考就是:haskell是真正的纯函数式语言吗?我觉得不是—–它超越了纯函数式。它是既允许命令式编程,又使用强大类型系统来把有副作用的代码与纯代码分离。这一点,令它强大无比。

[1] 这不是绝对…其实有个方法:unsafePerformIO。不过我觉得应该辩证地讨论它。

理解continuation

Posted on 六月 6th, 2009 in 笔记 | 4 Comments »

当时小,不懂事,初学函数式编程时一头就扎的就是continuation和monad,一直搞不明白就一直放着。上个星期在ShiningRay老师的这篇《简介延续“Continuation”》里看到:

def call_cc(f,c):
     f(c,c)

貌似很泪流满面的样子,没想到这东西有这么简单。之后在图书馆里写了一个小时的伪代码,貌似搞明白了。按照Continuation Passing Style(cps)的设定,函数没有返回值,而是用函数的运算结果调用函数最后一个参数,很简单吧。不过那些特性又是从何而来呢,像保存状态尾递归优化之类?现在想想,之前之所以不理解,大概就是因为不会写cps的递归吧,其实动手写的话也就那回事。国父孙先生不是说么,知难行易。

如下伪代码,求前n个自然数的和:

def sum(n):
    if (n==0): 0
    else :
        n+sum(n-1)

换成等价的前缀形式(if就懒得改了,知道这回事就好):

def sum(n):
	if (n==0): return 0
    else
        return add(n, sum(sub(n,1)))

好,换成cps:

def sum(n,c):
    if (n==0): c(0) #“延续”下去,而不是返回
    else:
        sub n, 1, (\x1 -> #一个lambda,匿名函数
        sum x1, (\x2 -> #递归在这里
        add x2 ,n ,c))

再一个迭代的例子:

def iter_sum(n, r):
     if (n==0) : return r
     else : iter_sum(n-1, r+n)

换成前缀:

def iter_sum(n,r):
     if (n==0): return r
     else : iter_sum(sub(n, 1), add(r,n))

cps:

def c_iter_sum(n,r,c):
    if (n==0): c(r)
    else:
        sub n, 1, (\x1 ->
        add r, n, (\x2 ->
        c_iter_sum(x1, x2, c))) #尾递归

可以看出,cps中引入了些自由变量,把函数求值的结果放在堆里而非栈中,于是就可以实现不限深度的递归。不过这样貌似增加了垃圾收集的负担,没有银弹哇。

contiuation中只有“延续”而没有“返回”,每一步“延续”都是对后面函数的调用,通过一条函数与函数的链构成了顺序结构。ShiningRay老师貌似说过,一个函数调用就是一个状态。callcc貌似就是把“延续”的下一个函数保存,从而保存了状态。Smalltalk的那个Seaside框架貌似就是把contiuation作为对象持久化,在下次访问时找到这个持久化的contiuation将状态还原,从而模拟出仿桌面程序开发的效果。貌似要比asp.net那WebForm的实现更加自然些。