显示标签为“google reader starred”的博文。显示所有博文
显示标签为“google reader starred”的博文。显示所有博文

2012年6月27日星期三

联俄抗美或是中国的战略错误



  前些日子,笔者到银行办事儿,顺手拿起一份《北京日报》,翻到评论版。头条是“从某某某事件看美国政客的拙劣表演”这篇雄文,二条是“胳膊肘般的感情”符合中俄战略利益。


  两篇文章结合起来,无疑是告诉读者,美国政客很坏,处心积虑地对付中國;俄罗斯真是哥们儿,应该珍惜并发展中俄之间的深情厚谊。


  作为黨报的《北京日报》的评论有时是中國官方的意志体现,有时是自发行为。这两条,无论是官方意志还是自发所为,都说明反美亲俄的姿态。


  拉俄罗斯抗衡美国,其实也不是什么秘密。


  最近,和一位中國外交部前高官以及一位东南亚问题专家聊南海问题。两位都集中火力谈美国,认为美国处处与中國为敌,俄罗斯才是真朋友。这位老大使,还向我透露了一个“秘密”。


  2月,在利比亚问题上中國投下反对票,令国内外大感意外。这位大使告诉笔者,本来中國想弃权,但普京发现任由西方这样颠覆一个又一个政权很危险,于是电令俄罗斯外交官投反对票,然后通知中國,中國这才投了反对票。


  难怪,众多国际问题专家听说中國投反对票时,瞠目结舌,不知为何这么干。


  其实,中俄之间在国际舞台上还有诸多配合,许多人认为这样符合双方利益,两个弱者联合对付一个强者古已有之。


  三国是吴国和蜀国两个弱者,联合起来对付强大的魏国;20世纪70年代美苏争霸时,为了缓解压力,打开了通往中國的大门,中美联合抗衡苏联。


  不要以为这么干理所当然地个中國带来好处,恰恰相反,联俄抗美将是中國最大的战略错误。


  从历史上看,俄罗斯是抢掠中國地盘最多的国家,而美国是二战中國要亡国灭种之际给予帮助最多的国家。


  新中國成立后,中國采取一边倒政策,彻底倒向苏联,结果一无所获,还在珍宝岛开战;改革开放和美国及其盟国做生意,融入西方体系后,经济才得以迅猛发展。苏联带给中國的是灾难和屈辱,而美国带给中國的是民主和普世价值。


  从政治体制看,俄罗斯表面是民主国家,实质是“警察国家”,在国际舞台上经常是出尔反尔,不讲信义。


  苏联失去了中國,失去了东欧,然后自己又分裂,显然是落后的体制。而美国及其盟友的民主体制,虽然有诸多缺陷,但依旧是这个星球上一系列坏制度里面相对较好的一个。


  从经济方面看,更是如此,中美经济合作,中國真是赚了不少钱,大家对中美之间的相互依存看得清楚。需要注意的是,虽然欧美经济出现困难,但你要相信他们自身的调节能力,不要以为中國真的多么厉害。


  再看看俄罗斯,领导一声令下,华商的财产就被俄罗斯警察抢走;中俄之间的管道,说改道日本就改道,毫不含糊。


  中國指望俄罗斯供应石油,更是天大的风险,俄罗斯倒是将扼住中國的咽喉,想断油就断油,想提价就提价,整你没商量。


  这是俄罗斯人的性格,他们多疑、善变、警惕心强,融合了西方的勇猛和东方的狡黠,他们不止对中國如此,对谁都这样。


  从人民之间的情感来看。美国人对中國人,还是有着传统的友好,当年把庚子赔款的钱,拿来建清华大学,便是美国人所为。


  而俄罗斯则不同,俄罗斯人一方面羡慕中國的经济成就,一方面难以掩饰多年来多中國的瞧不起和敌视,黄祸论在俄罗斯的流行程度,远大于中國威胁论在美国的流行程度。


  从地缘政治看,中美更不应为敌。中美远隔重洋,应该是天然的盟友,一个富强稳定的中國符合美国的利益,却未必符合俄罗斯的利益。


  基于上述原因,可以认为,联俄抗美不会给中國带来什么好处;反之,将让中國处于孤立地位,可能毁掉改革开放的成果,更有甚者,还可能面临更大的灾难。


  这些浅显的道理,为什么很多人不明白?原因很简单,有些人揣着明白装糊涂。


  中國外交界以及专家的传统是,到那个国家工作、研究哪个国家,就亲哪国,因此,对俄工作的人士希望中俄关系好,再正常不过了。


  但到了美国这里,却来了个180大转弯。在中國政府内部,甚至一些专家,越是了解美国,越是主张对美强硬,这样做的理由很简单——政治正确。


  王立军进入美国使馆,美国给足了面子,但为了政治正确,总要批判美国才安全吧?陈光诚进入美国使馆,说这是美国政客的拙劣表演,政治正确。


  中菲南海对峙有美国在背后,批判一番总是正确吧?美国发布人權报告,说中國是獨裁国家,中國立即也予以反击,批评美国的人權,隔空叫骂。


  当然,可以说这是中美双方互有默契的表演,但对民众而言,谁能分得清哪个是真、哪个是假?哪里是悉心表演、哪里是真刀实枪?


  其实,本来没有什么敌人,你如果把一个人当做是你的敌人,每天这么想,这么说,天长日久,他便真的成为你的敌人。


  天长日久,专业人士不得不为了政治正确表演,而随和国力强大,民族主义勃兴,很多人不满足于世界第二经济体,希望中國超越美国,成为老大。


  这是可怕的想法。如果这种想法蔓延,将会军备竞赛,毫无疑问,这将拖垮中國。


  其实,中國发展到今天,休养生息一下,与民谋利,夯实基础。


  王冲,曾任《中國青年报》国际部记者,《中國周刊》国际部主任,现为互联网从业者。


  作者:王冲




中国报道周刊, 2012-06-17. | 添加评论 | No comment


原文地址 联俄抗美或是中国的战略错误


通过Google Buzz关注 中国报道周刊


通过Twitter关注 中国报道周刊


通过RSS 全文订阅


通过电子邮件 全文订阅


文章分类 国际关系.


欢迎大家投稿,点这里发送投稿邮件


相关日志






2012年4月17日星期二

【外刊IT评论网】内疚的程序员





我发现,当程序员开发了一个项目,然后要把它移交给其他程序员时,他们会对开发这个项目时做出的一些决策感到内疚。我问他们当时为什么选择这样做,他们会羞愧的说,“唉,我知道这不是最好的实现方法,如果现在再去做,肯定不会采用那样的方式。”有些人可能会辩护,或强调一下外部因素,比如工期压力。但我的观点是,程序员不需要为老的项目感到太多的内疚。


经验


我承认,我曾经有一次重新发球的经验。那是一个作为内部工具使用的Ruby on Rails项目。我之前对这种技术架构了解不多。基本上就是把东西按照需求拼凑起来,它运行很正常。没有多少测试,设计上必然是没有体现出最好的设计原则。但它能用。


接着,我做了一个6个月长的Rails项目,过程完全是TDD的。在此之后,出现了一个机会,需要调整那个内部工具,增加一些功能。


我很高兴有这次机会。我感觉对这种技术有了更好的了解,能够看出代码中存在的问题,知道如何用更好的Rails或Ruby技术来解决这些问题。这让人很兴奋。不止一次,我惊奇于那些老的代码竟然能正常的运行。我想,绝大多数程序员都很少能有这样的机会,除非他们是在维护一个老项目,我想这是一次很有价值的经历,让我在事后看清了我自己写的程序。


综合分析


但后来,我开始意识到,程序员不必要为自己开发出的产品感到内疚。新的技术和实践方法不断的出现,等待着你去学习,每一次你都要权衡取舍,总会有事后诸葛亮的情况出现。我应该现在重构这个类,还是放到以后再说?我是需要把设计的容易扩展,或者根本不需要这样?做这个项目时我们是否应该首先尽量的减少技术上的风险?


在针对某一问题我遍历群书后,对解决这类问题我学会了新的技术,新的方法。但这并不能妨碍我们当前的工作。我们不可能百分百的知道我们所需要的知识,我们能想到的方案只是能满足解决当前问题需求。


我相信,程序员都已经尽了他们最大的努力。但这并不能免除程序员犯错误,并从错误中学到经验,也不能保证他们能够进行先知先觉的学习。


我想说的是,程序员如果没有足够的知识以最佳的方式来解决所有的问题或在困境中做出最正确的抉择,他不必为此不安。在之后的岁月里认识到了自己的错误,这是自己进步的标识。每一次都把事情做的正确无误,这暗示一种技术的停滞,或完美主义。哪一种更有可能?


你是否也有过这样的一种愿望,希望能够重新来一次,改变某个软件项目中的某些东西?有过看着自己写过的代码感到恶心的时候?把事情做对,还是把事情做完?平衡点在哪里?在评论里留下你的想法吧!




本文来自外刊IT评论网(www.aqee.net),原始地址:内疚的程序员




【外刊IT评论网】你做过的最有效的提高你的编程水平的一件事情是什么





最近在stackexchange网站上看到了一个非常好的问答,有人问:你做过的最有效的提高你的编程水平的一件事情是什么?


回首作为一个程序员这些年来的生活和职业道路,我使用了很多种不同的方法来提高我的编程技能 —— 阅读代码,编写程序,阅读书籍,听讲座,看视频,等等。

我的问题是:你做过的最有效的提高你的编程水平的一件事情是什么?对于那些想提高水平的程序员,你的建议是什么?

我希望你们提供的答案是各种各样的,并且不是那种“放之四海而皆准”的答案 —— 我希望得到适用于不同人的不同的答案。


有很多人给出了自己的答案,在这里,我将其中最受认可的前三种答案选出来翻译给大家。

最受欢迎的回答:学无止境



没有特别的先后次序…


  • 和比自己更聪明的人一起工作

  • 永远乐意听取他人的意见,不管对方是低级水平,一般水平,资深,还是大师。职称头衔并不代表一切。

  • 学习其它的框架/语言,学习它们是的工作原理和思想,拿它们跟你已知的技术做比较。

  • 学习各种设计模式,最佳实践理论,然后用它们检查自己先前的知识,在需要的时候使用这些模式。

  • 结对编程

反对Joel说的一切。 ;)


第二受欢迎的回答:成为多面手



争取成为一个‘多面手万事通’

在我职业生涯的早期,我在一种数据库和编程语言上是个专家。不幸的是,这种数据库在“数据库战争”中落败了,我才发现我的职业道路…很窄。在此之后,我下定决心以后决不能把自己封在一个小空间里。我开始学习所有手头上能接触到的东西:Windows,Unix,C,C++,Java,C#,Perl,Python,Access,SQL Server,Oracle,Informix,MySQL,等等。不管什么样的新的,不常见的工具或技术,我都成为“大拿” —— “去问克雷格(作者自己),他要是不会,他会去学会的。”结果,我做了各种各样的项目,从为环境监测做嵌入式系统,到为导弹防御做命令和控制系统。

我在各种的公司里唯一遇到的问题是:它们坚持要把我固定在一个专门的研究方向内,而我的专门研究是要成为一个多面手。[编辑: 也叫做学识渊博的人或多才多艺的人或多领域专家。]

有些事情需要留意 … 高科技界里知识的半衰期是多少?根据摩尔定律(Moore’s law):18-24月内,半数你学到的知识都会过时。错误的遵循这种规律的专家会轻易的在这种技术发展的压力崩溃;一个多面手要做的事就是不断的丰富自己的技能,并从应用这些技能的经历中吸取教训。


第三受欢迎的回答:不要跟臭棋篓子下棋



我一直认为自己在不错的程序员中也算是个“灌篮高手”。直到有个家伙——我们叫他艾伦——被招进团队。艾伦很显然在很多方面都比我优秀。也比我年轻。他让我认识到,在过去的这些年里,我没有多少长进。我是一个特定技术方向的程序员,而且是水平一般。

这惊醒我应该自觉的不断提高自己的水平,特别是我写的代码的水平。

艾伦引导我学会了很多东西。他告诉我,大部分我写的代码在今后的数年里都将一直维护和进行扩展,写代码时要将这点铭记在心。我应该为我的代码写自动测试程序。艾伦说代码的开发一定不能停止在第一版上,应该不断的重构,提炼,让它达到完美。我发现,我对这些语言和工具的使用都还有还很大的改进空间。

从艾伦那我学到的最重要的一件事情是:永远不要停止学习。

数年后,艾伦离开了公司。我的心里突然感觉空荡荡的。这些年与他为伴让我在技能上提升到了一个全新的水平,我知道现在我比团队里的其他人优秀很多。他们仍然写着糟糕的代码,犯着以前犯过的错误。我努力教育他们,但他们对此不感兴趣。事实上,他们讨厌有人这样傲慢自大的指出他们犯的错误。

于是,几个月后,我也离开这这个公司。我去了一个很小的公司,在一个很出色的团队里工作。那里每个人都渴望学习更多知识,我喜欢这样的。

我很幸运能遇到艾伦。没有他,我也许现在仍然待在那家死气沉沉的公司和那帮食古不化的家伙在一起,哪都去不了,想的全是自己的私利。


这个讨论在stackexchange网站上的地址是这里

从我个人而言,我觉得第三个答案对我最有价值,不知各位同行们有什么感受?请写在评论里与大家分享。



本文来自外刊IT评论网(www.aqee.net),原始地址:你做过的最有效的提高你的编程水平的一件事情是什么

【外刊IT评论网】一个女人的故事





大概是六十一、二年前的样子,一个年轻聪明的黑人女孩——格温——从多伦多艾伦比初级公办学校毕业了。她的老师给了她一张通知单,单子上有秋季她要进入的中级学校的地址,她很小心的把它带回了位于圣克莱门特大街——一个生活消费适中、主要是由中产阶级家庭聚集的地区——的家中。


洛伊丝夫人没有上过大学,但她对女儿格温抱有很高的期望。洛伊丝的父亲——格温的祖父——从巴巴多斯岛移民加拿大,就是为了要让他的子孙们有一个更好的前程。洛伊丝的几个兄弟——勒桑和伦纳德——都上过大学,勒桑是一个工程师,曾为彩色电视的生产制作发明了好几项技术。


洛伊丝看了通知书,目瞪口呆。格温将要去的是另外一个镇子上的职业学校,这种学校里,年轻女孩们学的是如何缝纫、烹调、打字,年轻小伙们学的是如何修理汽车或浇灌混凝土。


第二天,洛伊丝来到校长的办公室。洛伊丝想知道,为什么她的女儿去的不是几条街外的北多伦多学院这样的传统大学。是她没有达到分数线吗?格温在学校里表现不佳吗?校长宽慰她说,格温在职业学校里会过的很开心的,她会学到一门手艺,在她建立一个家庭前的,这些手艺对她会有很大帮助。洛伊丝很生气,但没有办法。学校已经做了决定。


洛伊丝并不是这么容易被屈服的。几天后,她再次来到校长办公室,一起同来的还有她的“家族成员”。格温的祖父和叔叔们拥挤在校长办公室里,肆意的表达着他们对学校这样对待格温的事情的自己的观点。三个男人都很强硬,校长态度软化了。


北多伦多学院

北多伦多学院



于是,九月份到来时,格温去了北多伦多学院,在那里久负盛名的管弦乐队里担任第一小提琴手,这培养了她一生对音乐和舞蹈的热爱。等她毕业后,她进入了多伦多大学,她是她的家族里第一个拥有这样高学历的女性。


像很多女生一样,格温经常去一些舞会。在一个这样的舞会中,她注意的了一个小伙,按她自己的形容,是目前为止在那里见到过的跳舞跳的最好的小伙。他的名字叫查尔斯,是个白人,他个头很高,他让她想起了美国百老汇舞蹈家阿斯泰尔。他特别爱体育运动,尤其是滑雪,整个冬天在西部工作和滑雪,夏天返回到安大略省。


他们一起跳舞,他们坠入爱河,他们结婚了,他们想在附近租一间体面的公寓。事实证明,这是不可能的。在美国很多州里,他们的婚姻是不合法的。在多伦多,他们可以结婚,但他们无法合租一个公寓,因为房东怕惹上“麻烦”。


他们只有买一套房子才能生活中一起,他们就这样做了。这样要比租房子住贵的多,于是他们两个都不得不出去工作。格温搜索报纸上的分类公告,她发现Empire Life保险公司真正招聘年轻人做“数据处理”工作,没有工作经验要求。他们邀请应聘人进行一个“试戏”式的面试,格温于是就去了,按时,而且穿着整洁。


老式计算机,打孔机

老式计算机,打孔机



按她自己的回忆,她是唯一一个女性。也是唯一一个黑人。一大片年轻人排成排站在一些桌子前,那里有几个女人在分发测试题。当格温排到了队伍最前面时,一个女人想对她做一些指点。“我们是在招聘打字员,但你进错了房间。”格温已经学会了如何表现出强硬,也学到了一些小窍门。并且,她需要这份工作。


“何不让我试一下呢?没有任何害处?”


对方耸了耸肩,她获得了一次测试的机会,拿到了那根已经削好的铅笔。有几张空着的桌子,她选了一个坐下,没有理会来自其它应聘者异样的打量,专心开始答题。很多的题都是关于数字的,例如猜测一个序列里下一个数字是什么。有一些题是逻辑智力题,例如,你需要弄清楚骑自行车的人是面包师,住在有一扇红色的门的房子里的是机械师。有一些很奇怪的问题,例如,一个三维立体图形的草图,就像一个立方体,上面少一些方块,她需要猜出什么形状的小块能过补上这缺少的地方,或哪几个小块经过翻转或扭动能做到同样的效果。


答完了这些问题后,格温把它交了上去,等待着有人告诉她下一步该做什么。当有人叫她的名字时,一个老人陪着她进入了一个单独的房间。老人看着她,非常的惊奇,等看完了她的答卷后,他问了她很多关于她的教育和家庭背景的问题。他思考了一会,然后走出屋子叫来了一位同事。这个同事很不友好。他想知道,是谁指挥她来做这场恶作剧的。


格温很困惑。什么恶作剧?这个同事认定她在作弊,是有人事先告诉了她答案。这一幕就像是几十年后的电影《贫民窟的百万富翁》里的场景的重现,两位面试官尽他们最大的本事来试图让她承认:她在作弊。他们告诉她,她的分数太优秀了,不可能是真的。直觉就可以告诉你一个年轻的黑人女人不可能在一个专门为计算机编程而设计的智能测评中获得99分。


IBM电子数据处理机

IBM电子数据处理机



计算机什么


计算机编程。Empire Life公司从IBM购买了一台计算机,就像今天的许多公司一样,他们需要开发出软件来使他们的业务处理过程自动化。除了提供硬件外,IBM公司还提供招聘和培训所有的职员使用这些新系统,包括程序员。面试官辗转于各个客户,为他们安装计算机,培训受过教育的青年如何对IBM的计算机进行编程,他们清楚的知道何等优异的候选人才能拿到格温这样的分数。


他们试了各种各样其它的问题,其它考试的测试题,用于更高级候选人的问题。格温尽力给予回答。两个男人惊呆了。至此,他们终于信服,她没有作弊,他们知道她将会成为一个不可多得的人才。他们推荐把她按照程序分析师来培养——给了她程序分析师这最资深的职位。她完成了培训,成为了加拿大第一位女程序员。格温将要去领导多伦多市保险业一大批大型计算机化的项目开发工作。


如今她已经退休,像大多数退休者一样,她让她的孩子帮着她使用计算机。她喜欢苹果电脑,在网上做一些卖书买书的小业务。对于打破这样一个由男性统治的行业她所面对的困难,她会说些什么?


“我很轻松。计算机并不在意我是一个女人,或我是一个黑人。大多数女人比我要辛苦的多。”




本文来自外刊IT评论网(www.aqee.net),原始地址:一个女人的故事





via 外刊IT评论 http://www.aqee.net/a-womans-story/

【外刊IT评论网】那些关于如何提高效率的文章都是在虾扯蛋





Hacker News上和reddit的编程板块上有很多关于如何提高效率方面的专家。几乎每周,我们都会遇到有不同的人声称他们的工作效率提高了45.67%等等。有点像Oprah的访谈节目。在某些幸运的日子里,我们会被告知使用X web应用,使用这个应用的作者推荐的敏捷方法,你能如何的最小化员工的皱眉头的时间。你应该听说过关于使用Vim如何改变一个人的生活的故事吧。


让我把真相揭示于天下。阅读这些关于如何提高效率的文章,其本身就是一种十分没有效率的活动。如果你把这些时间用于观看Reddit上的那些猫呀狗呀的也许会更好。请思考这样一个事实,你这些年来读的所有的这些如何提高效率的文章并没有丝毫提高你的工作效率。你早应该用你的理智认识到这些关于如何提高效率的文章都是废话。


你也许会打断我说,“可是Jason,我知道有人在听取了Twitter上{这里是某位杰出程序员的名字}的忠告后,现在每天能写出2千行代码。”不错,我也知道这个家伙。可我也听说有很些人被闪电击中而死的这种巧事。


那本篇文章是否是一篇能提高工作效率的文章呢。也许吧。这篇有特殊用意的文章能通过劝阻你不要再读那些关于如何提高效率的文章来真正提高你的工作效率。如果它是一篇能提高你工作效率的文章,我希望它是你读的最后一篇此类文章。




本文来自外刊IT评论网(www.aqee.net),原始地址:那些关于如何提高效率的文章都是在虾扯蛋





via 外刊IT评论 http://www.aqee.net/productivity-posts-are-bullshit/

【外刊IT评论网】为什么我愿意为某个老板干活而不去做IT创业





当知道了我要为微软工作后,一个朋友问我“为什么你要给那个人干活?为什么不去IT创业呢?”我的回复差不多是“我喜欢每两周领一次工资的生活”,但其实还有更多的原因。



不错,这正常的朝九晚五的工作的一个最大的好处是稳定。我有健康保险,休假日,薪水收入也不错。这并不是我不想IT创业的最大原因。最大的原因是,我还没有找到一个我们足够感兴趣,愿意全部精力都投入到其中的目标。


我知道,如果我草率的与人合作,完成他人的某个理想,我不会有足够的热情来完成那些创始人们需要处理的所有的零零总总的烦事。如果我自己成立一个公司去IT创业,我将需要自己处理诸如工资结算,账务,法律等问题。我现在不想做这些事情。我想的是集中精力做出一些很酷的玩意儿。


那么,当你为老板干活时,对于遇到的那些让人厌烦的事情怎么办呢?这些事情已不再重要。如果我忘记了提交任务进度,经理会发邮件通知我。如果我忘了偿还公司内的账务,后果只会稍微严重一点点。


我不需要成立一个IT创业公司。我可以以一个程序员的身份加入一个公司,而且能对这个公司产生重要的影响。这毫无置疑是有一定的吸引力的,有朝一日也许我会成为这样的人。现在,我只想为“某个老板”干活,很高兴能看到我将要去开发的软件能被百万人使用。




本文来自外刊IT评论网(www.aqee.net),原始地址:为什么我愿意为某个老板干活而不去做IT创业





via 外刊IT评论 http://www.aqee.net/why-im-working-for-the-man-and-not-doing-a-startup/

【外刊IT评论网】为什么我们要学习Haskell这样的编程语言





最近的几个月,我一直在学习一种叫Haskell的编程语言。由于里面有太多的从未遇到的编程概念,整个过程就像是完全重新学习如何编程。在i.TV网站上,我写了很多JavaScript(node.js和前端代码)。虽然有不少的函数式/haskell式的编程模式不能引用进来,但仍有大量的技术思想让我在使用javascript编程语言时受益不少。


你会发现Haskell库里有能够处理各种事情的各种各样的函数。起初我以为这些只是一种技术上的积累,但随后我认识到,这些函数相比起其它语言里的函数,它们能应用到形式更广泛的问题中。这使得它们更有价值,因为我们都不太喜欢对一些常见的问题还不得不自己去写解决方案。


这些函数是可以相互组合1 的:它们能针对性的解决某些问题,而不对你的代码做任何依赖,所以,你可以拼装它们,组合成一个能够解决你的大问题的东西。


高阶函数(Higher Order Functions)


在Haskell语言中,最多的被反复使用的函数都是高阶函数(higher order functions)——能以函数作为参数、能返回函数的函数。这使得它们具有固有的灵活性。下面是一个不太灵活的函数:它计算一个数组里等于某个值的元素的个数。



// 不灵活
function countMatching(array, value) {
var counted = 0
for (var i = 0; i < array.length; i++) {
if (array[i] == value)
counted++
}
return counted
}

// == 2
countMatching([1,3,3,4,5], 3)


它不灵活,因为它只能用来计算一个数组中精确匹配某个值的元素的个数。


下面是一个灵活一些的版本,它能接受一个函数,而不是一个值,作为参数。我们可以用它来对任何数据、任何对象进行比较。



// more flexible
function count(array, matching) {
var counted = 0
for (var i = 0; i < array.length; i++) {
if (matching(array[i]))
counted++
}
return counted
}

// == 2, same as first example
count([1,3,3,4,5], function(num) {
return (num == 3)
})

// == 2, now we can use our functions for ANY kind of items or match test!
count([{name:"bob"}, {name:"henry"}, {name:"jon"}], function(obj) {
return (obj.name.length < 4)
})


因为高阶函数更具灵活性,你就更少有机会去写它们,因为你一旦你写成一个,你可以它应用到各种不同的情况中。


可重复利用的比较函数


你可能注意到了,count函数的写法比countMatching更冗长。但是,虽然count函数可复用了,但比较函数2 却不可复用。如果是一些简单的情况,这就足够了,但经常,我们会需要更复杂的比较方法的函数。这样的函数不仅仅可用于计数,它们可以用于任何事情上,一但你写成或找到了这样的函数,从长期的角度看,它们会节省你大量的时间和调试功夫。


让我们来定义一个可复用的比较函数,达到我们的目的。==不是一个函数。我们是否可以定义一个eq函数来帮我们完成类似的事情呢?



function eq(a, b) {
return (a == b)
}

count([1,3,3,4,5], function(num) {
return eq(3, num)
})


我们向前迈进了一步:我们用了一个库函数来完成比较任务,而不是使用我们现写的代码。如果eq函数很复杂,我们可以测试它并可以在其它的地方复用它。


但这使代码变得冗长,因为count函数的参数是一个只需要一个参数——数组元素——的函数,而eq函数却需要两个参数。我还是要定义我们自己的匿名函数。让我们来简化一下这些代码。




function makeEq(a) {
// countMatchingWith wants a function that takes
// only 1 argument, just like the one we're returning
return function(b) {
return eq(a, b)
}
}

// now it's only on one line!
count([1,3,3,4,5], makeEq(3))


我们写了一个兼容count函数的函数(一个参数——数组元素——返回true或false)。看起来就像是count函数调用的是eq(3, item)。这叫做偏函数用法(partial function application)。


偏函数用法(Partial Application)


偏函数用法(Partial Function Application)是指创建一个调用另外一个部分参数已经预置的函数的函数的用法。这样,它就能被别的地方,比如count函数,以更少的参数形式来调用。我们在makeEq函数里已经实现了这些,但是,我们并不想针对我们各种功能开发出各种版本的makeX(比如makeEqt,makeGt,makeLt等)函数。让我们来找一种方法能通用于各种形式的函数。



function applyFirst(f, a) {
return function(b) {
return f.call(null, a, b)
}
}

count([1,3,3,4,5], applyFirst(eq, 3))


现在我们不再需要一个makeEq函数了。任何2个参数的库函数,我们都可以按这种方式调用。通过偏函数用法,使得定义即使是诸如==这样简单功能的各种函数都变得十分有意义,我们可以在高阶函数中更容易的使用它们。


对那些超过2个参数的函数如何办呢?下面的这一版本3 能让我们接受任意多的参数,高阶函数可以自己追加参数。



function apply(f) {
var args = Array.prototype.slice.call(arguments, 1)
return function(x) {
return f.apply(null, args.concat(x))
}
}

function propertyEquals(propertyName, value, obj) {
return (obj[propertyName] == value)
}

count([{name:"bob"},{name:"john"}], apply(propertyEquals, "name", "bob")) // == 1


我们预置了2个参数,“name” 和 “bob”,count函数补足了最后一个参数来完成整个调用。偏函数用法使我们能接受各样的函数为参数,例如eq,然后把它们用于各样的高阶函数,例如count,以此来解决我们特定的问题。


配合ES5的 Map 和 Filter 功能函数的偏函数用法


ES5里有很多非常好的高阶函数,underscore里的数量更多。让我们看看filter函数——一个接收比较函数、过滤数组内容的函数。



// this equals [1,3,3]
[1,3,3,4,5].filter(function(num) {
return (num < 4)
})


让我们把它替换成一个可以复用的比较函数lt (less than)。



function lt(a, b) {
return (a < b)
}

[1,3,3,4,5].filter(apply(lt, 4))


看上去添加这个lt函数的做法有点傻,但是,我们可以使用偏函数用法来创造一个很简练的比较函数,当这个比较函数变的很复杂的时候,我们就能从对它的复用过程中获得好处。


map函数能让你把数组里的一个东西变成另外一个东西。



var usersById = {"u1":{name:"bob"}, "u2":{name:"john"}}
var user = {name:"sean", friendIds: ["u1", "u2"]}

// == ["bob", "john"]
function friendsNames(usersById, user) {
return user.friendIds.map(function(id) {
return usersById[id].name
})
}


我们写一个可以复用的map变换函数,就像之前我们的可复用比较函数一样。让我们写一个叫做lookup的函数。



function lookup(obj, key) {
return obj[key]
}

// == [{name:"bob"}, {name:"john"}]
function friends(usersById, user) {
return user.friendIds.map(apply(lookup, usersById))
}


很接近要求,但我们需要的是名称,而不是friend对象本身。如果我们再写一个参数颠倒过来的 lookup函数,通过第二次的map可以把它们的名称取出来。



function lookupFlipped(key, obj) {
return lookup(obj, key)
}

// == ["bob", "john"]
function friendsNames(usersById, user) {
return friends(usersById, user)
.map(apply(lookupFlipped, "name"))
}


但是我不想定义这个lookupFlipped函数,这样干有点傻。这样,我们来定义一个函数,它接收参数的顺序是从右到左,而不是从左到右,于是我们就能够复用lookup了。



function applyr(f) {
var args = Array.prototype.slice.call(arguments, 1)
return function(x) {
return f.apply(null, [x].concat(args))
}
}

// == ["bob", "john"]
function friendsNames(usersById, user) {
return friends(usersById, user)
.map(applyr(lookup, "name")) // we can use normal lookup!
}


applyr(lookup, "name")函数返回的函数只接受一个参数——那个对象——返回对象的名称。我们不再需要反转任何东西:我们可以按任何顺序接受参数。


偏函数用法需要对一些常见的功能定义各种不同的函数,就像lt函数,但这正是我们的目的。你可以以偏函数用法把lt函数既用于count函数,也可用于Array.filter函数。它们可以复用,可以组合使用。


函数组合


在之前的例子中,我们遍历了数组两次,一次用来获取users,一次为了获取names。如果能在一次map映射操作中同时做这两件事情,效率会高很多。



function friendsNames(usersById, user) {
return user.friendIds.map(function(id) {
var friend = lookup(usersById, id)
return lookup(friend, "name")
})
}


我们得到首次lookup的结果,把它第二次传入lookup函数组合意思是串联多个函数,组成一个新的函数,每一次串联都是把前一个函数的输出当作下一个函数的输入。


让我们来写一个能这样运转的高阶函数,利用它把friendsNames函数重写成一个只需要单次map操作的函数。需要注意的是,函数串联的执行顺序是从右到左的,就跟你写出f(g(x))这样的代码的运行方式一样。



function compose(f, g) {
return function(x) {
return f(g(x))
}
}

function friendsNames(usersById, user) {
return user.friendIds.map(compose(applyr(lookup, "name"), apply(lookup, usersById)))
}


对数组的遍历只进行了一次,只使用一次map操作,跟我们头一个例子一样。


我们不能使用我们写出的friends函数,因为它既包含了如何取出一个friend的业务逻辑,也包含了map操作。friends函数是不能复用的,它的职责太多了——它是针对特定事物的。如果你们再写一个friend函数,让它只map一个friend,写一个name函数,让它返回对象的名称呢?



var friend = lookup // lookup 恰巧能干我们想要的事情。
var name = applyr(lookup, "name")

function friendsNames(usersById, user) {
// this line is now more semantic.
return user.friends.map(compose(name, apply(friend, usersById)))
}


相较于定义一个既包含转换操作,又包含遍历操作的friends函数,我们只定义了一个可做转换操作的friend函数,而我们已经有了map函数为我做变换操作。friend函数比friends函数更具复用性,因为它包含更少的特定业务逻辑,能在更多的情形中使用。


这里你能找到更多的关于JavaScript里函数组合的信息。


函数式和功能单一化让你的代码库更整洁


我发现我的很多的JavaScript代码都是从无到有自己写出来的。这不仅仅是说比起使用现成的程序包要效率低,它还会暗藏更多的bug,更难阅读和维护。使用高阶函数和偏函数用法,我们可以写出可复用的程序库,每个函数都精准的对应解决它们能解决的一部分问题。


随着时间的推移,项目会变得越来越复杂,各部分越来越耦合,如果我们拥有的是一个能够各自独立测试不依赖的程序库,我们的项目会从中受益,变得更健康,更稳定。




  1. 一种宽泛的组合。并不特指函数或对象组合,只是一种你用小东西组建大东西的思想。




  2. “Matching functions”被称作predicates,但我这里不想引入新的编程术语。




  3. 这里有更通用的apply实现。






本文来自外刊IT评论网(www.aqee.net),原始地址:为什么我们要学习Haskell这样的编程语言





via 外刊IT评论 http://www.aqee.net/learn-you-a-haskell-for-great-good/