循环迭代器和闭包

Mar 6, 2008

Comments

通常, C 程序员使用如下代码对 a 数组的每个元素进行操作:

for (i = 0; i < n; i++) func(a[i]);

这行代码有三个独立的逻辑, for 循环控制了对 a 的访问顺序, a[i] 控制了对 a 数组的元素访问方式, func() 函数控制了对 a 元素的操作. 这个三个逻辑是彼此独立的. 然而, 问题逐渐浮出水面. 首先是 for 循环的次序. 对于随机存取的数组 a, 访问顺序应当是没有关系的. for( i=n-1; i>=0; i–) 也是可以的. 一个简洁的语言应当突出逻辑, 丢掉不必要的代码. 因此, 最好能写成

foreach (k in a)  func(k);

这个解一石二鸟, 第一是把访问顺序逻辑彻底抛弃, 第二是改变了访问方式, 从此没有烦人的 ArrayIndexOutOfBoundException, 不需要担心访问越界. 在函数式编程语言中, 类似的形式是:

map(func, a)

我们希望 foreach 能够遍历一个数据结构的每个元素一次. 可是这个终究是一个语法糖, 因为它只能胜任特定的数据结构. 对于用户自己设计的一些数据结构, 比如树, 想同时拥有先序和后序遍历, foreach 就无能为力了. 与此同时, 我们也不想用 for 那样简单粗暴的方式去控制访问顺序 (因为很容易导致内存越界, 而且很多数据结构不支持随机存取). 这时候, 就需要迭代器的帮助了. 因为不同的数据结构要求不同的访问顺序, 我们希望数据结构本身能够提供一些访问顺序. 这种对于数据结构上元素访问顺序的抽象, 被称为迭代器. 一般来说, 迭代器通过 getIterator() 被数据结构构造, 具有一个 hasNext() 的判断和一个 next() 的函数. 对一个数据结构的访问可以四海一家的写成:

for (i = a.getIterater(User’s_Order); i.hasNext(); i.next() ) func(i.current());

迭代器把访问逻辑从数据结构上分离出来, 是一个常用的设计方法. Design Pattern 也把它作为23个Pattern之一.在 STL 中也到处都是了它的身影. 但对一个完美主义者来说, 这个代码还是太冗长, 既然对数据结构的访问能够四海一家的写成如此, 为何不直接规定一个简洁的语法访问呢? 是的, 我们希望返朴归真, 回到原来的形式:

for i in a.SomeIterator(): func(i)

好消息是现代语言都支持这样的方法. [注: 在C/C++ 语言中, 还不能支持上面的写法. C#有类似的写法. 在 Ruby 和 Python 中很常见. ] 可是能不能再简化呢, 能不能连 i 这个中间变量都不要呢? 我们简直希望写成:

a.SomeIterator(func)

是呀, 这样的世界多美好啊. 可是, 别忘了在面向对象的语言中间, 一切都是对象. 在 C 的时代, 我们可以通过函数指针把 func 参数传递进去. 可是这里是对象, 怎么办呢. 很简单, 只要构造一个只有一个方法的对象, 传进去就行了. 这样的构造方法, 居然也是一个设计模式, 叫做函数对象(Function Object), 或者叫函数子 (Functor). 被 Java 的匿名内部类这个概念折腾到崩溃的读到这里, 应该知道所谓的匿名内部类, 就是为了在面向对象的环境中做函数传递这个事情而想出来的小花招. Java 的写法就是

a.SomeIterator( new FunctionObject()

{ public func(a)

{return something;}

});

[为了引用这样一个函数, 使用了天书一般的不必要代码, 可想有多少人真的喜欢这个方法]

逃离了Java 的世界, 我们来到 Python 或者 Ruby 或者其他函数式语言的世界, 激动的发现原来函数也是一种对象, 和其他对象一样在 Python 中坐上头等舱. 如此好事怎么能错过呢. 于是, 大摇大摆写上:

a.SomeIterator(func)

没有类型检查, 也没有复杂代码, 连一个辅助变量都不多谢, 真舒服. 在 Python 中间, 这样的模式比比皆是, 比如 os.path.walk(path, visit, arg) 可以对path目录下所有的文件遍历, 并且调用 visit 函数处理, 还可以夹带一个私货 arg 进去, 非常方便. [注: os.walk() 则反其道行之, 提供一个 generator, 外部用 for 访问]

从外面夹带私货不算特别困难, 毕竟可以通过修改函数的定义方式来实现. 可是假如想从迭代器里面夹带一些私货出来给函数用, 就有点困难了. 比如说, func 函数需要访问迭代器的一个私有的变量. 显然把迭代器作为参数传给函数是不行的. 只能反其道行之, 让迭代器把函数当成自己人, 以迭代器为主, 把函数包含到迭代器的作用域内才能玩转. 这个就是所谓的闭包. 也就是说, 一个函数被包入另一个更大的作用域, 并且可以访问大的作用域里面的变量. C/C++ 是不允许在函数里面定义函数的, 所以只好望着闭包干羡慕. Java 算不错了, 用内部类解决了这个问题.

我们说个具体的例子: 函数 func(x) 需要另一个值 y, 返回 x*y, 另一个值 y 在外部作用域定义了. 写成 Python 代码

a= [1, 2, 3]

def func(x):

return x*y

for y in a:

print func(2)

会出现 2,4,6

我们可以看到, 函数func 的定义和使用是独立的. 而静态语言是不能随便在什么位置都能定义函数闭包的, 原因不难解释: 编译器会跳出来告诉你 y 这个变量没有定义. 因为动态语言在运行时才能得到 y 的值, 从而使用 func, 所以不存在这个问题. 动态语言的灵活性在此充分展现. 最后, 既然我们知道迭代器后面必然要加一个闭包, 还要括号干啥? 不如直接写成 (实际上, Groovy 语言就是这样的):

a.each func

从简单的循环, 到迭代器, 到生成器, 到内部类, 到函数作为一级对象, 再到闭包, 过程式编程语言, 对象编程语言和函数编程语言越来越呈现融合的趋势.


请懂量子力学的一起帮我参详一篇论文

Feb 23, 2008

Comments

文章名:

Ultimate Physical Limits to Computation [计算的终极物理极限]

作者: MIT 的 Seth Lloyd,  量子计算领域顶尖科学家.

概要:  计算机是一种物理系统,因此肯定服从物理系统的规律。文章研究了一千克的计算机最多一秒能执行多少次逻辑运算,最大存储容量是多少,并且给出了定量的结果。所以, 摩尔定律不能永续。

这些问题和我以前提到的比特每焦耳问题是很相似,但是我物理基础有限,不能全部理解。

本文发在 2000 年 Nature.地址: 

http://puhep1.princeton.edu/~mcdonald/examples/QM/lloyd_nature_406_1047_00.pdf

有兴趣的直接给我发邮件或者gtalk: xu.mathena [A@T] gmail.com


为什么不给中国压岁钱

Feb 20, 2008

Comments

最近广大网民过完年, 度过南方雪灾后, 开始盘点国际社会对中国的支</wbr>援压岁钱, 结果大失所望,我们国家这次接受的援助少得可怜。还有好事者把美国当年飓风受灾的各国捐款表拿出来。乖乖, 几乎世界上所有国家都给美帝捐款了,而且都是百万美元级别, 连敌人古巴和委内瑞拉都主动提出帮忙. 孟子说 “得道多助,失道寡助”, 看来横行世界的霸权主义美帝还比我们支持亚非拉民族独立反对伊拉克战争的中国的小兄弟多么? 到底哪国得多助, 列位看官自行判断.

《论语》中的一句话 “邦有道, 危言危行; 邦无道, 危行言孙”. 其中这个 “邦有道”, 翻译成大白话就是 “这个国家是个和谐社会”, “危” 在古文中,一般做”高”讲。 这句话就是说, 和谐社会啊,您就说说高尚的话,做做高尚的事情. 简单的说就是遵守</wbr>八荣,反对八耻. 不和谐社会呢, 您行为还是要继续高尚, 但是说话得像孙子, 得怂”.

回到前文。这次雪灾的新闻报道中文的大家看的很多了,我们看看英文报道,看看官方新华网是怎么向世界宣传我们的灾情的. 没有一句提到灾民,郴州告急,京珠高速堵塞,南方电煤告急,众多农民工缺少御寒衣物等等. 我们全是正面的, 全是国家领导人一线抗灾, 一句对任何人的批评和抱怨都没有(连著名敌台VOA和BBC都客观报道了灾民的处境). 想起美国飓风那年,中国国内民众都知道数万人失去家园,军警镇*压*暴*乱,布什政府救助不力. 一边是和谐社会高歌歌颂抗灾模范, 对媒体严格控制负面报道; 一边是不和谐社会媒体和灾民拆政府台, 报道灾民恶劣处境, 抱怨政府无能. 政府说话像孙子, 害怕媒体和灾民生气. 这些情况, 全世界人民都看在眼里的. 好比两个乞丐同时在前门外卖唱要钱,一个穿得西装革履,说有信心重建家园; 另一个把烂疮都露出来让人看到了. 哪怕后一个乞丐面前的帽子里面放满了钱, 你还是会给他钱. 而对前一个乞丐, 除了认识, 知道他是要面子的人给点安慰之外, 其他人能给钱,打死我也不信啊.

所以, 与其怪列强小气, 怪美国不讲义气. 不如好好想想,为什么人家不帮我们? 寡助的原因是不是因为我们失道了?

PS:

《论语》 一共六次提到 “邦有道” ,分别是:

  1. 子谓南容,”邦有道,不废;邦无道,免于刑戮”。以其兄之子妻之。 (公冶长)
  1. 子曰:”宁武子邦有道则知,邦无道则愚。其知可及也,其愚不可及也。” (公冶长)
  1. 子曰:”笃信好学,守死善道。危邦不入,乱邦不居。天下有道则见,无道则隐。邦有道,贫且贱焉,耻也;邦无道,富且贵焉,耻也。” (泰伯)
  1. 宪问耻。子曰:”邦有道,谷;邦无道,谷,耻也。” (宪问)

5.子曰:”邦有道,危言危行;邦无道,危行言孙。” (宪问)

  1. 子曰:”直哉史鱼!邦有道,如矢;邦无道,如矢。君子哉蘧伯玉!邦有道,则仕;邦无道,则可卷而怀之。” (卫灵公)

一一解释。

第一条说的是孔老师相侄女婿的故事。孔老师评价他的学生南容说, 他呀,和谐社会肯定能有一番做为,就算在不和谐的社会,也能保证不掉脑袋。孔老师运用概率知识,数学期望这么一算,就把侄女嫁给他了.

第二条说的是卫国一个大夫(不是医生), 两朝元老。在不和谐社会中做官的时候,假装智商低于80, 不说话;到了和谐社会,立即变的聪明起来。孔老师感叹说,这个人聪明的时候大家还能效仿效仿, 这个人模仿笨蛋的那个本事啊,我都学不来.

第三条很有意思,说是我们要好好学习,建设和谐社会。像伊朗朝鲜那种见天就被推翻的国家呢,我们不要去,连签证都不办。像伊拉克巴勒斯坦这种乱糟糟的国家呢,我们千万不能在那里买房定居。和谐社会我就出山做做官,从从政;不和谐社会呢,我就打打牌,喝喝酒,看看小书听听戏。和谐社会你不做做大官不发财,那简直是耻辱。不和谐社会你发财做官才是耻辱。

第四条和上面意思一样。一个叫宪的人问孔老师,什么叫 “耻” 啊。孔老师说了, 和谐社会你食君之禄,担君之忧是荣耀;不和谐社会你丫还出来做官助纣为虐,就是耻辱。第六条也是评点人物的。 说的是子鱼这个人,不管国家是否和谐,都是正直得像箭一样。伯玉这个人也是,和谐社会就出去做官;不和谐社会就读读书,怀才隐居.

各位读者可以从这些和谐社会对人生选择的影响上,思考一下到底什么是和谐社会,你的危言孙行或者危言危行程度是否反映了社会的和谐程度.


别离

Feb 17, 2008

Comments

我外公前几天去世了, 我很想他.

外公一共有五个儿女,孙辈七人,我唯一不在国内. 长辈都说不要担心家里. 我的担心,其实就是打个电话而已,其他什么事情都帮不了忙了。

一月十日我去北京,去和老人家道别。握握手,说声我走了,他嗓子呜呜哑哑,眼眶湿润。外公的病是小脑萎缩,几年前,还能读书看报,神闲气静;玩牌下棋,智深勇沉。 06年的时候,还批评我妈把我送这么远,送我的时候还说了几句宽慰的话。谁想两年下来,等我回去看他的时候,都没有了行动和语言能力。

外婆怕外公难过,催我快走。我隐隐觉得怕是最后一次见外公了,握手好久。九十岁的外婆怕他难受,离别情怯,催我出门,自己却站在门口台阶上,伫立良久,目送我消失在视线里。我突然想到一句话:一赴绝国,讵相见期。

从小时候到大,家里面老了人,我都正好在外面,都隐隐感到可能是最后一次见面,都不得不走。生离, 死别,即如此。

乔木千里,北梁永辞

参商阴阳,魂动泪滋

我很想念他们!


为什么有这么多的人生精华要分享?

Feb 11, 2008

Comments

今天上午起床头疼,加上没课,于是请假没去学校. 午觉后, 打开电脑,想想没什么事情,就打开一百年没去的SNS, 比如校内网,海内网,若邻以及 Facebook, 大过年的用 SNS 给各位朋友拜个年.

海内网写满了每个人的签名,Facebook 也很喧嚣. 相比于美国的原版 Facebook 和 Linkedin, 气象不同的是校内和若邻,他们充满了 某某分享了某某日志 这样的提醒。我随机抄10条吧:

  1. 12种一定要改的生活习惯
  1. 13条左右人生的金科玉律。
  1. 记住这些关键的东西吧.可怕,但有用——希望我的朋友都看到这些
  1. 大学生春节回家必做的六件事
  1. 如何成为一个起早者-关于睡眠
  1. 一个HR给应届毕业生的面试建议 后悔看到的太晚了
  1. 让你的精力旺旺的25种方法
  1. 你MP3里不可缺少的137首欧美歌曲
  1. 离开校园要做的最后20件事
  1. 中国最好的十个职业排名

每篇标题都是那么的吸引人,都看上去那么有用. 真的那么有用么,或者看过能记住么? 我看未必. 以我经历为例,我大四面试的时候看了无数的面经,等到面试结束,尘埃落定,体验无非就是自信和实力而已。而那些强记的面试技巧,现在一个都想不起来了。 从1997年开始,我开始阅读《读者》,每期的那些哲理小故事,好像是一盏明灯,指导心灵。到了99年,我上高中,突然没机会订阅了;我发现周围同学悟到的人生体验,和我一字一句读到抄到小本子上的那些“格言”,是类似的,或者说,根本就是相同的,虽然他们没有看过《读者》。而我在现实中,同样在格言的指导下,我做事情却很少比那些城市长大的同学做得好。我知道,这个不是聪明的问题,读书少的问题,是环境和经验的问题。

我并非编排分享这些好文章的好友,也不是批评《读者》杂志。 我们这个时代真是最好的时代,人生体验和生活技巧之类的东西,唾手可得,甚至都推送到面前,只要鼠标一点,眼睛一扫,仿佛天下真理,人生精华,都被浓缩吸收了。可能分享者,阅读者,都觉得这些文章有道理,自己有同感。其实,这种认同感其实是不需要通过阅读这样一篇文章来实现的,因为你早就领悟并且实践了,现在只不过和别人殊途同归。 在我眼里, 如果一篇人生经验让你觉得”对的对的,万分同意“,那其实你已经在生活中悟到了并且内化了这些,并不需要阅读那些文章,你在生活中也能一样如鱼得水;如果一篇人生经验让你觉得”冷汗直冒,欠缺万分“,这样的文章才是真的十全大补的,才是需要详细阅读的。 而一篇让你不屑的人生经验,可要当心了,往往这些就是前车之鉴。

我这些天读到的文章,如 13 条左右人生的金科玉律,就是觉得写的太好了,太放之四海了,以至于我不知道该怎么吸收。英文中有一个叫做 too…to 的句型,表示 “太..以至..”, 这13条,太是真理了,以至于我不知道在生活中何处使用他们. 而生活是一种体验型产品, 真实体验的人生经验,才是精彩的;读来的强记下的那些经验,其实都不是经验,直到用过一次以后才是。可往往用之前你又忘了这些人生经验了。

就像学数学是理解而不是记公式一样, 我宁愿看到这些格言经验的撰写人一开始处处碰壁,慢慢悟道,让我们看到他到达这些真理的轨迹。我愿进入他们的环境,学会他们的思维方式,从而领悟到这些经验,而不愿意被他们喂着,结论多,思考少。理解了过程和逻辑,结论显然。

[同样的逻辑,如果这篇文章没有能让我的读者感到有点收获,我会为此感到歉疚。文章本是一点小感想,写下来给自己看的,不过既然您订阅了,阅读了,我就对为你付出的时间有所回报才是。还有就是,以后我如果写感悟,一定注意写下思考过程。过程比结果重要。]