5

我为什么不再做 PL 人

 3 years ago
source link: http://www.yinwang.org/blog-cn/2016/03/31/no-longer-pl
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

我为什么不再做 PL 人

我不做程序语言(PL)的工作已经半年了。在这半年里,我变得快乐了很多,对世界也有了新的观点。现在我想来讲一讲,我为什么不想再做 PL 的工作和研究。我只希望这些观点可以给正在做 PL,或者考虑进入这个领域的人们,作为一份参考。

学校里的 PL 人

PL 看似计算机科学最精髓的部分,事实确实也是这样的。没有任何一个其它领域,可以让你对程序的本质形成如此深入的领悟,然而这并不等于你就应该进入 PL 的博士班。这是为什么呢?

PL 这个领域几十年来,已经发展到了非常成熟的阶段。这里面的问题,要么在 20 年前已经被人解决掉了,要么就是类似“停机问题”一样,不可能解决的问题。然而,博士毕业却要求你发表“创新”的论文,那怎么办呢?于是你就只有扯淡,把别人已经解决的问题换个名字,或者制造一些看似新鲜却不管用的概念,在大会上煞有介事的宣讲。俗话说就是“炒冷饭”。

最开头进入这个领域的时候,你可能不觉得是这样,因为似乎有那么多的东西可以学习,那么多的大牛可以瞻仰,那么多的新鲜名词,什么“lambda calculus”啊,“语义”啊,各种各样的“类型系统”啊,这样那样的“逻辑”…… 可是时间久了,看透了,你就发现一些这个圈子里的规律。

几乎每篇 PL 领域的论文,里面必有一页弯弯曲曲,让人看花眼的逻辑公式。程序语言的论文,不是用程序来描述,而是用一些眼花缭乱的逻辑符号,像这样:

图1:PL论文里的公式

绝大部分 PL 领域的专家们,似乎都酷爱逻辑符号,视逻辑学家高人一等。这种崇尚古人的倾向,使得 PL 专家们看不见这些符号背后,类似电路一样的直觉。他们看不见逻辑学的历史局限,所以他们也许能够发展和扩充一个理论,却无法创造一个新的。

说到古人,却并不是所有古人都这么晦涩。如果你考古一下就会发现,其实现代逻辑学的鼻祖 Gottlob Frege 最初的论文里,是没有这些稀奇古怪的符号的。他整篇论文都在画图,一些像电路一样的东西。比如下图,就是 Frege 的创始论文《Begriffsschrift》里最复杂的“公式”之一:

图2:Frege的“公式”

你可以把这里的每根线理解成一根电线。图 1 里那些诡异的逻辑符号,都是一些好事的后人(比如 Gentzen)加进去的,最后搞得乌七八糟,失去了 Frege 理论的简单性。所以 PL 专家们虽然崇尚古人,却没发现大部分古人其实并没获得鼻祖 Frege 的真传。

如果你看透了那些公式,自己动手实现过各种解释器,就会发现 PL 论文里的那些公式,其实相当于解释器的代码,只不过是用一种叫做“xx 逻辑”的晦涩的语言写出来的。逻辑,其实是一种相当落伍的程序语言。如果你精通解释器的代码,也许就会发现,这些公式其实用蹩脚的方式,实现了哈希表等数据结构。

逻辑语言只运行于逻辑学家的脑子里面,用它写出的代码一样可能有 bug,而且由于这语言如此障眼难读,而且没有 debugger,所以 bug 非常难发现。逻辑学家们成天为自己的设计失误和 bug 伤透了脑筋,PL 专家们却认为他们具有数学的美感,是比自己聪明的高人。

所以当你看透了所有这些,就会发现 PL 的学术界,其实反反复复在解决一些早已经解决了的问题,只不过给它们起了不同的名字,使用不同的方式来描述。有时候好几个子领域,其实解决的是同一个问题,然而每个子领域的人,却都说自己的问题在本质上是不一样的,号称自己是那个子领域的鼻祖。甚至有人在 20 多年的时间里,制造出一代又一代的 PhD 和教授职位。他们的理论一代代的更新,最后却无法解决实际的问题。所谓的“控制流分析”(control-flow analysis,CFA),就是这样的一个子领域。

不知道谁是真的高人

进入一个领域做研究,你总该知道那些人是真正厉害的。可惜的是,PL 这个领域里,你往往不知道谁是真正掌握了精髓的学者,甚至好几年之后你仍然蒙在鼓里。我的历史教训是,写教科书的人,往往不是最聪明,最理解本质的。真正深刻的 PL 研究者,你可能根本没听说过他们的名字。

一般程序员提到 PL,就会跟“编译器”这个领域混淆在一起,就会想起大学时候上编译器课,看《龙书》时焦头烂额的情景。然后由于斯德哥尔摩综合症,他们就会崇拜龙书的作者们。直到遇到了真正厉害的PL专家,你才发现编译器这个领域,跟 PL 根本是两回事,它其实比 PL 要低一个档次,里面充满了死记硬背的知识甚至误导。龙书的作者,其实也不是最厉害的编译器作者,他们更不是合格的 PL 专家。

上过“正统”的 PL 课程的学生,往往用一本经典大部头教材叫《TAPL》,然后就会误认为此书的作者是最厉害的 PL 专家,然而他们再一次被名气给蒙蔽了。TAPL 这书其实不但照本宣科,没有揭示实质,而且冗长没有选择,有用的没用的过时的理论,一股脑的灌输给你。等你研究到了所谓“交集类型”(intersection types),看到 TAPL 作者当年的博士论文才发现,其实他把简单的问题搞复杂了,而且那些理论几乎完全不能实用。真正厉害的 intersection types 专家,其实默默无闻的待在 Boston University,而且研究到最后,intersection types 这个领域其实被他们证明为完全不能实用。

由于 TAPL 这本书,以及 ML,Haskell 等语言在 PL 界的“白象”地位,于是很多人又对 Hindley-Milner 类型系统(HM)充满了崇敬之情,以为 HM 系统的发明者Robin Milner是最厉害的 PL 学者。他的确不错,然而等你随手就能实现出 HM 系统,看清了它的实质,就会发现所有这样能够“倒推”出类型的系统,其实都具有很大的局限性。

HM 系统的“unification”机制,依赖于数学上的“等价关系”,所以它不可能兼容子类型(subtyping)关系。原因很简单:因为子类型没有交换性,不是一个等价关系。而子类型关系却是对现实世界进行直观的建模所必不可少的,于是你就发现 Haskell 这类基于 HM 系统的语言,为了弥补这些缺陷而出现各种“扩展”,却永远无法达到简单和直观。一开头就错了,所以无论 Haskell 如何发展,这个缺陷也无法弥补。如果没有了 HM 系统,Haskell 就不再是 Haskell。

Robin Milner 的另外一个贡献 π-calculus,虽然看起来吓人,其实看透了之后你发现它里面并没有很多东西。π-calculus 对并发进行“建模”,却不能解决并发所带来的各种问题,比如竞争(race condition)。实际上普通的语言也能对并发进行简单的建模,所以 π-calculus 其实只停留于纸面上,不可能应用到现实中去。跟 π-calculus 类似的一个概念 CSP 也有类似的问题,属于“白象理论”。很多语言(比如 Go)扯着 CSP 的旗号,引起很多人无厘头的膜拜,可见白象的威力有多大。

我在学校研究 PL 的时候就是这样,每天都发现天外有天,每天都发现曾经的偶像其实很多时候是错觉。最后我发现,PL 领域其实最后就剩下那么一点点实质的内容,其它的都是人们造出来的浮云。所以每当有人问我推荐 PL 书籍,我都比较无语,因为我的 PL 知识只有非常少数是看书得来的。自己动手琢磨出来的知识,才是最管用的。

没人知道你是谁

PL 的学生还有一个问题,那就是毕业后工作不好找。只有极少数公司(像微软,Intel,Oracle)里的少数团队,可以发挥 PL 专家的特殊才能。绝大部分其它公司根本不知道 PL 是什么,PL 专家是干什么的。你跟他们说你的专业是“程序语言”,他们还以为你只是学会了“编程”而已,还问你想做“前端”还是“后端”。诚然,PL 学生一般都有很好的编程能力,然而公司往往只关心自己的实际需求。PL 学生毕业之后,很容易被普通公司作为没有任何专长的人对待。

另外,PL 的圈子相当的小,而且门派宗教观念严重,所以就算你从名师手下毕业,想进入另一个老师的门徒掌权的公司,很可能因为两个门派的敌视而无法被接纳,就算进去了也经常会因为对于 PL 的理念不同而发生冲突。所以,学习 PL 最精髓的理论是有好处的,然而进入 PhD 投身 PL 的研究,我觉得应该三思。

公司里的 PL 人:过度工程

PL 人在学校里跟着教授炒冷饭,毕业进入了公司之后,他们的行为方式还是非常类似。他们喜欢在公司里做的一件事情,叫做“过度工程”。本来很直接,很容易解决的一个问题,非要给你扯到各种炫酷的 PL 名词,然后用无比复杂的方案来解决。

有一些 PL 人喜欢推广他们认为高大上的语言,比如 Haskell,OCaml,Scala 等。这些语言在 PL 学术界很受尊重,所以他们以为这些语言能够奇迹般的解决实际的问题,然而事实却不是这样的。事实是,这些学术界出来的语言,其实缺乏处理现实问题的机制。为了能够在学术上证明程序的所谓“正确性”,而且由于类型系统本身的局限性,这些语言往往被设计得过于简单,具有过度的约束性,以至于表达能力欠缺。

最后,你发现用这些语言来写代码,总是这也不能做,那也不能做,因为你要是那么做了,编译器就无法发现“类型错误”。到最后你发现,这些语言的约束,其实是无需有的。如果放宽这些约束,其实可以更优雅,更简单的对问题进行建模。对正确性的过分关注,其实导致了 PL 人选择蹩脚的语言,写出绕着弯子,难以理解的代码。

还有一类 PL 人,喜欢设计不必要存在的语言。因为他们认为设计语言是 PL 人的特异功能,所以随时随地都想把问题往“语言设计”的方向上靠。这样的趋势是非常危险的,因为有原则的 PL 人,其实都明白一条重要的道理:不到万不得已的时候,千万不要制造语言。

很多 PL 人在公司里盲目的制造新的语言,导致的问题是,到最后谁也无法理解这种新语言写出来的代码。这一方面是新语言必然导致的结果,另一方面是由于,并不是每一个 PL 人都有全面的知识和很好的“品味”。每个 PL 学生毕业,往往只深入研究了 PL 的某个子领域,而对其它方面只是浮光掠影,所以他们有可能在那上面犯错。

有些 PL 人喜欢照猫画虎,所以可能盲目的模仿 Go 语言,Haskell 或者 Python 的特性,设计出非常蹊跷难用的语法。这些新的语言,其实让其他人苦不堪言。最后你发现,他们声称新语言能解决的问题,其实用像 Java 一样的老语言,照样可以很容易的解决。

喜欢钻牛角尖,把问题搞复杂,就是很多公司里的 PL 人的共同点。制造语言是 PL 人应该尽量避免的事情,这恰恰跟 PL 人的专长是矛盾的。所以有原则的 PL 人,生活怎么可能不苦。

PL人的天才病

很多研究 PL 的人喜欢看低其它程序员,认为自己能设计实现程序语言,就是天之骄子。我之所以从 Dan Friedman 那里学到了好东西,却没有成为他的 PhD 学生,一方面就是因为看不惯围绕在他身边那些自认为是“天才”的人。

总是有那么一群本科生,自认为掌握了 Friedman 所讲授的精髓,所以高人一等。于是我就经常无奈的看着他们,吵吵闹闹的宣讲他们解决的“新问题”,貌似什么了不起的发明一样,受到 Friedman 的肯定就受宠若惊的样子。而其实呢,那些都是我几年前就已经试过并且抛弃的方案。

其它的 PL 人,包括 PhD 学生,也有一样的毛病。不管在三流大学,还是在 Harvard,Princeton,MIT 这样的“牛校”出来的,只要是 PL 人,几乎必然有这种天才作风。另外你可能不知道的是,牛校往往并不产出优秀的 PL 人才。像 Stanford,Berkeley,MIT 这样的传统 CS 牛校,其实在 PL 方面是相当差的。

这种天才病的危害在于,它蒙蔽了这些人的眼睛。他们不再能设计出让“普通人”可以容易使用的产品。如果你不会用,他们就会嘲笑你笨,而其实呢,是因为他们的设计不好。他们喜欢用含混晦涩的方式(所谓“函数式”)的写法来构造代码,让其它人阅读和修改都极其困难。

这些所谓天才,看不到简单直观的解决方案,为了显示自己的聪明而采用繁复的抽象,其实是一种愚蠢。真正的天才,必须能够让事情变得简单。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK