Haskell中概念的理解(一)

刚才看了Bryan O’Sullivan的一个演讲《Running a startup on Haskell》,讲公司招人以及使用Haskell的一些现状。很赞同Brayan说的一句话“if cerntain skills are really widely distributed in a population they become completely meaningless”,如果某个技术非常流行,说懂这个东西毫无意义,如果一个人在简历里写他懂PHP懂Java,就像是在告诉别人他长了个脑袋。

断断续续学习Haskell也好几年了,没事的时候就会拿它作为一种思维训练,试图准确理解其中的概念,但是智力实在不够,每次多理解一些而已。最近好像突然领悟了很多(不敢说“想通”),不知是不是量变到质变的一个过程。

最近连续读了很多材料,有些是以前读过但未理解的。回想这个过程,应该是从理解Polymorphic Typechecking开始,读的是Basic Polymorphic Typechecking,主要收获是了解了大致的算法,对datatype(type constructor)有个更具体的感知。学习Haskell,理解类型多态很重要,只有理解了它才能理解typeclass和高阶多态,其实类型多态很像C++的模板,只是用在type constructor的定义中让人感到理解困难而已,尤其是type constructor中包含函数时,考虑下datatype中类型变量的顺序问题会有助于理解这个问题。然后重读了《Learn You a Haskell for Great Good!》第八节“Making Our Own Types and Typeclasses”,这一节算起来读过不止一次,但仅这次完全读懂,对类型理解也更加深刻,尤其是我感到自己可以很容易的理解StateMonad那诡异的s->(a,s)了,于是开始读一些Monad的tutorial

这几年学Haskell,大部分时间都花在Monad上,很早就会用,但是理解不到这个东西的好处,以及Monad到底如何“隔离副作用”,更别提自己在何时、如何设计一个Monad了。最近这块感悟比较多,有几个重要材料值得参考。Haskell两本免费教材《Learn You a Haskell for Great Good!》和《Real World Haskell》中Monad相关章节很重要。《All About Monads》对每个常用的Monad都有讲解,文中第一段直指Monad核心,理解这句话就理解了Monad,但是理解这句话是结果,试图理解这句话本身并没有太大意义;文中提到Monad的三个重要属性Modularity、Flexibility、Isolation ,其实这三个属性说的是一回事,理解这点很重要,同样理解这点是结果,另外要理解One-Way-Monad以及为什么Maybe不是One-Way-Monad,这是隔离副作用的关键。然后是Brian Beckman的视频“Don’t fear the Monad”,这个视频我很早以前看的时候还以为他讲跑题了,这次看完才恍然大悟,Brian的Bind类型推导过程也很精彩,看的时候回想一下《All About Monads》的第一段。正如Brian也提到的,其实Monad的所有魔力都在于那个bind(>>=)函数,每个Monad有自己个性化的bind。对于One-Way-Monad,这个函数使得我们可以操作m a中的a,而不会将a泄露出去,这是Monad的隔离性。一组相同的Monad(如IO)可以放到一个do-notation里执行,也就是combining computations,这种组合方式其实是一种模块化,它将一类操作关联到一处,而不影响其他部分,举例说,如果出现大量的嵌套case+Maybe语句,就可以将这些Maybe放到一个do-notation里,精简代码而又永远不会出错,因为与Maybe有关的计算都在bind里定义了。这样一个do-notation其实代表了某一类型Monad的一个计算序列(bind),而其计算的内容在其内部(类型m a的a)无法被外界直接取得,除非通过bind,也就是《All About Monads》的第一句话,“A monad is a way to structure computations in terms of values and sequences of computations using those values. ”

理解Monad之后才发现,其实这个概念并不难,理解它也并不一定需要范畴论的知识。让我吃惊的是发现在haskell中,这东西并不是什么重要的组成部分,举个不恰当的例子,就好像微积分在量子物理学中的作用一样,这是个必备技能,但根本没有触到关键。学习Haskell的难点还在于类型上,从类型的角度思考问题,通过类型来做问题抽象,才是困难之处。

下面说说typeclass,这是haskell中的一个核心概念,从SPJ的一个分享来看,这个东西最初只是一个实验功能。可以从Mark P. Jones的paper《Functional Programming with Overloading and Higher-Order Polymorphism》中找到这个概念诞生的原因。typeclass是为了解决任意多态类型所存在问题的一个折中方案。考虑函数size(例子瞎举的),它返回“某个数据结构的的大小”,如果希望它是多态的,而不是每次都要定义某个类型自己的sizeA::A->Int,sizeB::B->Int的话,就需要定义size::a->Int,但是如果不对a的类型加以限制,就可以将没有size的类型应用于这个函数,导致运行时错误,这是haskell这类静态类型语言所无法容忍的。于是typeclass出场了,通过定义一个typeclass叫做Countable,并将size定义为size::Countable a => a -> Int,对于每个应用于size的类型,都要求其为Countable的instance,否则类型检查失败,这样就非常优雅的解决了这个问题。可以看出typeclass更加接近interface。总之,它最初的出现是为了让haskell更精确的做类型推导,不会出现运行时错误,同事保持多态的优美。我前面说它是个折中方案是因为,(我认为)它其实是一种人工向编译器提供类型信息的方法,同时增加了不小的编码成本。

Mark P. Jones的paper非常优秀,其中不仅讲解了typeclass,还介绍了kind system,这是理解haskell类型系统的一个重要部分。有时间要细读读Mark以及Simon Peter Jones, Simon Marlow, John Hughes, Philip Wadler这群神人的paper,正是由于Haskell背后有这群人,这门语言才会这样魅力四射、引人入胜。

Haskell中还有很多其他内容没有花时间去学习理解,比如并发和Arrow,估计近期也没太多时间了。

狮子山下

人生中 有欢喜
难免 亦常有泪
我哋大家 在狮子山下
相遇上 总算是欢笑多余唏嘘
人生 不免崎岖
难以 绝无挂虑
既是同舟 在狮子山下
且共济 抛弃区分求共对
放开 彼此心中矛盾
理想 一起去追
同舟人 誓相随
无畏 更无惧
同处 海角天边
携手 踏平崎岖
我哋大家 用艰辛努力
写下那 不朽的香江名句

方向这事

最近一直在想,什么是属于我的可以从事一生的事情,或者什么事情“I do it because I must”。

若把生活比作操作系统,理想是Kernel,而现实是User-Space,作为我所实现的这个低效劣质的操作系统,它将大量时间用在了上下文切换上。随之而来的结果是,看似忙忙碌碌,却没有做任何有效的工作。

另外一个与之相似的类比是“产品”和“技术”,随着工作时间的加上,对周围人和事的理解也跟过去有所不同。十一看杨澜主持的“正青春”,贾樟柯导演的话令我印象非常深刻,他将人生分为两类,一类是“消费型人生”,一类是“创造型人生”,我认为很准确很透彻。环顾周围,每个人属于哪种类型一目了然。我们可以借用这两个概念来理解不同人对“技术”的不同态度(只考虑IT从业者)。对于“消费型”的人,更多的是认为技术仅仅是一种手段,且不是单一手段;对于“创造型”的人来说,可能技术本身就是目的,技术在他们心中更接近“科学”与“本质”。就如同人们对待数学的态度一样。我相信大部分人是消费型,包括很多自我划分为创造型的人。

最近对技术方向也进行了一些思考,计算机行业发展到现在,俨然成了一座森林,很容易迷失其中。沿着林中的河流走,却发现这里既有几条主流,也有许许多多的支流,没有人知道尽头是什么在哪里。选择一个可以持续保持兴趣和热情和方向不容易,所以最近广泛涉猎了一些领域,从高层到底层。目前对底层的兴趣更大一些,喜欢那种纯粹精炼的感觉,研究了一下OSv的代码,从github上可以看到所有的提交记录,研究代码的过程中也是一次很好的学习过程,另外还有lguest的代码,基本通读一遍。只是工作内容不是这些,难免都有分心。很想像Jserv他们一样,成立一下小型实验室,志趣相投的人一起做一些有趣的事情,少了浮躁的纷争。于是开始认真考虑一些事情。

前些天在内网搜索虚拟化相关的内容,一直找到外网上的一篇文章,那里几个大厂的内核组的人在一起聊工作,说其实内核相关的大头工作还是技术支持和参数调优,提交patch的机会很少。一阵心灰意懒。

好像什么事都经不住一句“为了什么”。

《逻辑的引擎》

前些天列了一个表,列出了二十世纪计算机各个领域的主要基础性paper,其中有很多开创性的paper,譬如Lambda算子、SVM等。谨记阿贝尔的忠告,“向大师学习,而不是他的学生们”。开始之前,为了对那个时代的大师以及他们所作的工作有个大致的了解,买了这本书。周末本想做些没做完的工作,结果打开书看了几页一发不可收拾,从中午一直看到深夜。

该书从莱布尼茨讲起,讲到布尔和布尔代数,到弗雷格的大厦以及这座大厦不稳固的基础,然后到康托尔的乐园和失乐园,再到希尔伯特及他的数学预言,最后到哥德尔的不完备定理和图灵机,酣畅淋漓,一气呵成,翻译也很不错。书中有很多重量级大师客串,比如亚里士多德和罗素,爱因斯坦和冯诺依曼,当然,冯诺依曼也可算是一个主角。

二十世纪初的这几个年代,是逻辑学空前辉煌的年代,思之令人神往不已。这个时代的数学家对数学本质的探究,对人心灵的数学和哲学层面的探究,都是其他年代无法比拟的。读完高德尔一章之后,深深感到,与这些大师相比,我们的人生毫无价值,从无知到有知耗费了太多光阴,又与自身的特异性做了太多错误的无畏抗争。二十几年里所做的,无非是无知的行为和对身体里异常基因的纠正。这些都是毫无意义的。磨掉了自身特异的部分,也就磨掉了成为传奇的一切可能,此时再迷茫再斥诸哲学,应该是得不到任何结果的。说起哲学,记得某位哲学家说过,“生命的意义只能在生命之外找到”,这些年我一直认为这只是一句故弄玄虚的断言,如今才明白,这是哥德尔不完备定理的一个简单推论。数学证明了哲学。

书中讲到很多以前不知道的事情,比如布尔的小女儿是《牛虻》的作者,哥德尔和爱因斯坦相熟识。

晚上看到某位112岁同学的博客,内心激起莫名感受,下班回来的路上,心里突然平静了好多。世界上究竟还是有些相似的人吧,他们讲着自己的故事,表达着自己的看法,念叨着自己的孤独,偶然间某些话与你的经历和感受重叠,或是你看懂了什么,于是不由的一阵感动。不过,这倒不是常有的事——虽相忘于江湖,却能相濡以沫。

要沉淀

这几个月,看了一些书,大部分是非技术,有《眠》、《与全世界做生意:一个经济学家的环球冒险》、《定位:有史以来对美国营销影响最大的观念 》、《MBA教不了你的创富课》、《习惯的力量》、《史玉柱自述:我的营销心得》、《柳井正与优衣库:你所不知道的优衣库成功秘诀》、《心理学统治世界》、《摩根写给儿子的32封信》等,其中几本的内容是挑着看的。摩根的家书我很怀疑其真实性,那些絮絮叨叨的心灵鸡汤跟摩根的名言“深思,慎言,不留文字”很不符,更像是高中作文,不过有格林斯潘作序,除非这个序也是杜撰的。有很多感触很深的地方,《MBA》中分析的“蓝海战略”和利润率计算,《习》中的“核心习惯”一章,《柳》中散落各处的“内心很透彻”,都非常精彩。

读《柳》时,我正坐在回家的动车的一等舱里,舒适的座位、久违的放松加上这书精彩的内容,我甚至希望火车一直这样走下去,不要停下来。这本书有两点比较让人感慨。一是相比肤浅浮躁的互联网行业,做实业的人更接近生意人和企业家的本质,同时成功的人也有从生意人到企业家的转变过程,相反互联网行业却像是电平转换,成王败寇,充斥着白日梦、投机心理,依赖的是讨巧、时势和忽悠。当然这么理解有点过激,但刚读完书时这种感受非常强烈。还有一点是柳井正本人,卖衣服卖成日本首富,这是非同寻常的成就。他本人是实干家,每次看到他分析自己,或讲过去事情时言语里流露出的某种东西,我就会想到曾国藩。他们都是内心非常透彻的人,也只有内心透彻的人才能成就顶级的事业。我是一直这么认为的。

技术上,入职以后没有太多长进,心态也比预想的差很多,实在有愧于心。先前定的今年要把CoffeeScript解释器写完,后来又想把codezero的代码迁移到NROS上去,继续搞搞内核层面的东西,不要荒废了自己,但心态一直不对。回头想,跟上研两年折腾的这些事情有很大关系。思维一旦发散,聚拢起来就很困难。想是如此。

要沉淀。

Asm.js和Blink

在沈阳不想睡,用手机看RSS,看到John Resig刚出炉的博客。记得前些天还在群里跟大家聊说觉得现在浏览器不该出各种新语言,每种都编译成Javascript,而是应该出一个字节码标准,各平台实现自己的优化解释器。出一个标准不容易,更实际的做法是选择Javascript的一个子集作为“字节码”(编译目标),这正是Asm.js干的。其实很多事不是想不到,而是想到了没有做——跟没想到一样。目前Firefox针对Asm.js做专门优化,速度只比C++慢两倍,应该慢慢可以与Java不相上下。将来各JS引擎跟进,Web平台的运行能力将大大加强,必将催生出更多可能性。

最近看各个项目,发现成功的软件在于雕琢。软件架构、性能、接口不一定要完美,但是一定要完善才有真正的用户,否则只是玩票。所以人们虽然热爱开源,仍旧会选择有商业支持的平台和软件包,因为真正做事的时候,需要完善的文档和稳定的系统,也没有时间和精力去修复Bug。如果没有商业软件,开源软件也很难精益求精。

第二天回家就看到Google宣布开发WebKit分支Blink。自从Google宣布要关闭Reader之后,就很难估计它会做什么,不会做什么。Chromium会fork掉webkit应该说不让人意外。WebKit对于各平台的支持方式有点古怪,每个平台都维护一个相当大的Port,功能各异;主流Port都在主干里;构建方式很多种;WebKit1不是multi-process架构,WebKit2没用Chromium的架构,Chromium也不会用WebKit2;一方面要增加自己的功能,一方面还要照顾情绪,不改变WebKit的Shape,于是抱怨说“This has slowed down the collective pace of innovation”,其实就是觉得WebKit拖后腿了。Chrome也一直认为多个产品解决相同问题可以促进竞争和创新。不过近来有点怀疑“公司意志”或“集体意志”这类东西,文化固然存在,但非终端用户产品的关键决策仍然是几个人的头脑风暴,跟这几个人当时的处境和心态密切相关,存在很多偶然性和非文化相关的必然性(比如WebKit和Chromium,Google和Apple)。

Offscreen WebKit Rendering

Overgrowth使用Awesomium做UI,Awesomium是无窗口WebKit,将HTML元素直接绘制到用户自己定义的视频缓冲区里。效果看起来很不错,使用HTML和CSS来做UI开发效率也很高,尤其网络游戏这种需要大量UI的系统,很适合人手有限的小团队。Awesomium基于Chromium,集成了V8,相当于在app里加入了完整的浏览器功能,充分使用可以发掘出很多潜能,绚丽的HTML5和CSS3的效果,免费的脚本调试功能。问题是Awesomium是闭源的,而且只支持Windows, MacOX, Linux,不支持iOS和Android,个头还比较大,Win版有数个DLL文件(超过20M)。理论上Awesomium支持Android是可以的,但是iOS不可能,因为V8无法在iOS的沙盒里运行。Chrome的iOS版也有这个问题,在iOS上甚至Webkit也不能用自己的,换句话说iOS版Chrome只是Safari一个壳。

除Awesomium,还有一个berkelium。它是开源的,支持完整的JS和Offescreen渲染,同样基于Chromium,也意味着对与iOS支持基本不可能。berkelium的功能没有Awesomium那么完善。有点奇怪为什么都使用Chromium版的Port,而不是只用WebKit,毕竟需要的只是UI功能。(使用Chromium的原因是Chromium有一个“WebKit Embedding Layer”,这种方式不用修改WebKit或Chromium的源代码。)。

看了几个Port的代码,包括WebKitSDL、Awesomium(1.08)和berkelium,看上去自己写一个Port并不会很困难,Awesomium最初的实现只用了一周(Awesomium和berkelium都不是Port。我猜我还是没有完全理解。)。

有几个问题让人犹豫:

  • WebKit和Chromium开发速度太快,如果想保证自己的Port与开发库同步不太可能。
  • 不能用V8,JSC有点慢。理论上Offscreen渲染只将WebKit作为一个渲染库,在iOS上可以运行,但是V8由于使用JIT,不大可能跑在iOS上。
  • WebKit不同平台的构建非常繁琐,尤其是如果想裁剪功能。我在Ubuntu12.04上将源改成raring才能将包更新到可以构建。
  • WebKit和Chromium的代码非常复杂庞大,且开发方式让人望而生畏(Very different than Mozilla and other more developer-friendly projects; It IS possible to fix bugs in WebKit, but it’s very difficult to track WebKit development)。
  • 如果想精简WebKit的功能需要对代码相对熟悉,可能会很耗时间,比如搞清楚两条渲染路径(软件和硬件)。
  • 对于硬件加速不熟悉,尤其是嵌入式平台上。

说句玩笑话,如果做一款大小十几M的手机游戏,却要搞个8G内存的PC编译一个多小时,实在难让人心安。

几个定律

看了几个管理学领域的定律,很有趣。

第一个是彼得定律,作者是著名管理学家劳伦斯·彼得,定律的核心是:

在一个等级制度中,每个职工趋向于上升到他所不能胜任的地位。

换句话说就是,每一个职工由于在原有职位上工作成绩表现好,就将被提升到更高一级职位,直到无法胜任为止。该定律有一个推论:

每一个职位最终都将被一个不能胜任其工作的职工所占据。层级组织的工作任务多半是由尚未达到不胜任阶层的员工完成的。

这是一条让人灰心的定律,每个人最终都会到达自己无法胜任的职位。听起来像宿命一样,可能是技术能力所限,可能是管理能力所限,也可能是技术职位转向管理职位,无论究其根本是什么原因导致,这个原理的合理性毋庸置疑。只要我们渴望提升职位,最终都会到达自己无法胜任的层次。

到达彼得高度之后,有两种选择:一种是黯然离场,让有能力的人担当;另一种是进入帕金森定律。帕金森定律核心意思是:

在行政管理中,行政机构会像金字塔一样不断增多,行政人员会不断膨胀,每个人都很忙,但组织效率越来越低下。究其原因是管理者无能。

无能的管理者有三个选择,要么让位,要么找个能干的人帮自己,要么找两个平庸的下属。前两个威胁自己的利益,于是他会选择第三个,该效应会递归下降扩散开来,形成机构重叠、人浮于事、扯皮推诿、效率低下的行政管理体系。其实这就是中国政府的现状。

长尾理论也很有意思,也是最近很流行的一个词语。似乎没有明确定义,按我的理解,主要意思是说:聚集种类繁多小众商品形成的销售量,可以创造出与热门商品相匹敌的价值。过去的“二八定律”中“八”并非微不足道,而是和“二”一样具有价值,甚至更高。Google和Amazon都是典型的长尾公司。

还有一些有趣的定律,比如连续体理论,牢骚法则,雷鲍夫法则,比伦定律等。不过超Y理论说的对,没有什么一成不变的、普遍适用的最佳的管理方式。人是最复杂的动物。

GameDev

最近SSH告急,先是22端口被封,修改默认端口后IP被封,向linode请求修改IP地址后可以正常访问。这里要称赞一下linode的技术支持,每次都在10min内回复。以后不敢再用SSH代理了,从github上搜到一个shadowsock-nodejs,方便可用。

看了一会twitter,昨天@infinite_ammo发起一个话题: what obstacles get in the way of you making games? 很多人参与回答,有些共鸣和感触:

@forwardresent Everything seems so overwhelming to do solo, but I’m the kind of person who wants to do everything solo.
单干有点太夸张了,但是我就是那种什么都喜欢单干的人。

@ArtfulGamer Finding a balance between work (teaching) and gamedev. Bad: limited hours/day. Good: limited hours -> working efficiently.
在教书和游戏开发之间找平衡中。坏处:时间有限;好处:有限时间让人高效工作。

@graebor Trying to make too many of them at once, usually. I think I’m getting better at controlling this, though..
总想一次搞定很多事。呃,我想我已经在努力控制这事了。。。

@AlteredTree quite often, I get distracted by a new shiny idea and lose interest in the old one. I have a lot of half-finished projects…
我经常被一个新点子搞得对以前的点子没兴趣了,于是有了一堆半成品项目。。。

@0SCUR0 mental illness gets in the way of my game making. But sometimes it does the opposite. Double edged sword I guess.
做游戏的过程中,大脑常常会处于病态,不过有时候也有点用,估计是把双刃剑。

@OverworldTheme Also the uncertainty of it. When you’re working alone, it’s hard to gauge what is and is not working. Causes me much grief.
自己工作的时候,很难衡量哪些是工作,哪些不是(翻译错没?),让我很伤心。

@theuncommon Right now it’s the day job. Both the time spent there and the loss of energy afterwards. Can’t afford to leave… yet.
现在这(游戏开发)是日常工作了。时间和精力投入很多,陷太深了。

《指环王》杂感

这两天一口气把《指环王》三部曲看了一遍,加上前几天看的《霍比特人》,算是全了。电影以前看过一点,但只有一点点印象,这次才算看懂。整部电影最精彩的情节就是弗罗多、山姆和咕噜一起去魔多的那些戏,魔戒的隐喻、人性的弱点都展现得淋漓尽致。人在无法战胜自己欲望的时候变得极为卑贱,在欲望得到满足时又极为贪婪。人人都挣脱不了自己的欲念,有智慧的人会选择远离,这就是为什么甘道夫和阿拉冈对魔戒避之不及。《神雕侠侣》里杨过在小龙女跳崖后带上面具,可能也是一样的道理。不要被欲念征服,这是成事的一个基本前提。

其实最震惊的不是情节,而是电影特技。晚上跟同学聊天,感慨国内硬件技术的落后,其实软件的差距也非常巨大。这几天跟哥一起找网游玩,发现一件有意思的事——国产网游和代理网游光看游戏截图就一目了然。几乎所有国产网游无论大小,清一色的乡村非主流。今天在YouTube看了一下午游戏视频,目前尖端游戏引擎的视觉冲击力着实让人震撼。这些年国内网游市场对外不开放,且软件行业的技术一直比较透明,才使得国内这些大厂有机会自己慢慢搞研发,否则必将如汽车行业和芯片行业一样被人远远甩在后面,甚至早已出局。