特别节目·中文精读

唐纳德·克努特:算法、TeX、人生与《计算机程序设计艺术》

Donald Knuth: Algorithms, TeX, Life, and The Art of Computer Programming

计算机科学泰斗谈算法之美、TeX 的诞生、《计算机程序设计艺术》的漫长写作与人生体悟。

官方音频00:00 / --:--
中文精读由 AI 基于原始访谈改写,非官方翻译,可能存在偏差或错误;表述以原音频与官方文稿为准。说明

唐纳德·克努特(Donald Knuth)给自己的人生做过一次结算。如果给幸福打分,满分一百,他给自己打八十。在他看来,这件事本来就该这样设计。

「0.8 就够了。」这是他的原话。一个把《计算机程序设计艺术》写了五十七年还没写完的人,一个把 TeX 打磨到连页码的「2」都容不下的人,在幸福这件事上却给自己设了一个上限。他说,一个生物体如果百分之百快乐,那就像所有人都嗑了药,什么事情也做不成,系统会崩掉。所以快乐到八成就好,八成刚刚好,剩下那两成留给沮丧、留给清醒、留给你第二天早上还想爬起来干活的那点张力。

这就是克努特。技术问题他追求九点八分,人生问题他接受八分的自己。

Lex Fridman 的这期访谈录于 2019 年,是那一年的收官之作。地点在克努特的书房,他管那地方叫「魔法发生的地方」。他没有邮箱,Lex 为了约到这次对话费了不少周折。一个不查邮件、用铅笔在纸上写程序、一周工作七天的人,用了一百分钟,聊了算法、排版、文学、宗教、死亡,以及六十年没变过的极客思维。

IBM 650:只有两千个字的内存

1957 年,克努特还是凯斯理工学院(Case Tech)的大一新生。他在统计组打工,负责打孔、录入数据、再把数据拿到另一台机器上排序。有一天学校来了一台新机器,IBM 650。那台机器填不满一个房间,但很吵,面板上一排排灯不停地闪。

他当时并不着急用它。他手里有那栋楼的钥匙,能进去看,还能拿到一本手册。他第一次编程靠的是一台很大的打孔机。那台机器有两千个字的内存,每个字是十个十进制数字加一个符号位。做一次加法,大概要等三毫秒。听起来不赖。

「为什么是三毫秒?因为磁鼓转一圈要五毫秒,你得等。如果一条指令在磁鼓上的某个位置,你要等磁鼓转到位才能读出数据,再等几个周期去取下一条指令。如果那条指令不在预想的位置,你就只能干等。」(唐纳德·克努特)

他的大四那年,学校才拿到五十个字的随机存储器。五十个字,那时是宝贝。他们每次把六十个字一块的数据搬进随机存储器,用完再搬下一块。克努特把这套生活叫「写子程序,搬上去,再开始」。

Lex 问他,你当时能预测六十年后计算机的样子吗?克努特说,他被问过很多次「什么让你惊讶」,他能一口气列出二十几件。有一次一个采访者反过来问他:有什么是没让你惊讶的?他想了五分钟,一件都想不出来。

这个反问很像他。预测未来不在他的兴趣范围内,他盯着的是眼前这台机器到底在干什么,瓶颈在哪,下一行代码能不能更快。

极客的大脑长什么样

克努特反复用过「geek」这个词。他说五十年代 IBM 就注意到世界上存在这么一群人,于是登广告招聘,广告上写得很直白:「如果你下棋,来麦迪逊大道面试。」

他估计这类人大概占总人口的百分之二。这个比例在他整个职业生涯里基本稳定。现在可能变了,因为孩子们小时候的经历不一样了。

那么,一个极客看到的世界,和普通人看到的世界,差别在哪?

他给出两点。

第一点,是在抽象层级之间跳跃的能力。你能看到一个大问题,也能看到一个非常小的细节,而且能在两者之间自由穿梭。你知道要解决某个大问题,下一步就是把某个寄存器加一;你也知道加一之后会落到算法的哪一层。你不会真的想到电子的层面,但你知道那台磁鼓转一圈要多久,所以你知道这次运算是怎么完成的。调试的时候你一层层往下问:是打孔打错了,是指令写错了,还是寄存器里放错了东西。每一层都不一样,每一层你都能进去。

第二点,是处理非一致性的能力。一个算法有十个步骤,每步干一件不同的事,极客不觉得这有什么难受。很多纯数学的体系靠一两条普遍规则推演一切,而像克努特这样的人,可以跟一个比必要更复杂的系统共处。有时候他们造出来的系统就是比需要的更复杂,因为他们不认为没找到那条简单规则是什么大事。

这也解释了他的书为什么长成那样。《计算机程序设计艺术》从不止步于高层,也从不止步于低层。他把各层混在一起写。有人批评他的书应该写得「更好」,他承认这大概是对的;另一些人说,如果你就是这种思维方式,那这就是训练自己的方式。他一路混着层级写,一路练怎么在层级之间跳。

图灵:第一个百分百的正牌极客

克努特说,十九世纪那些大数学家,雅可比、波尔查诺、阿贝尔,可能多少带点极客的症状。第一个百分百的正牌极客,是艾伦·图灵(Alan Turing)。

他年轻时对图灵的了解只停留在可计算性理论和图灵机上,那听起来像非常纯粹、非常抽象的理论工作。很多年后他才知道,图灵设计过机器,给曼彻斯特的机器写过一份漂亮的说明书,发明了子程序,而且是个手上沾油泥的黑客。

还有一个细节他印象很深。图灵把数字倒着写,从左往右写,因为他用的机器内部就是这么处理的。他会把 π 写成 9 5 0 1 4 点 3。他训练自己像计算机一样思考。

「他训练自己那么做,因为他当时用的计算机内部就是这么工作的。」(唐纳德·克努特)

Lex 说,这就是极客思维。克努特说,对。

文学化编程:用两种视角看同一件事

一个以形式化方法著称的人,创造了「文学化编程」(literate programming)这个概念,主张程序应该写成给人读的文章,而非给机器执行的指令序列。这两者矛盾吗?

克努特的回答还是那套非一致性哲学。他不相信「一种尺寸适合所有人」,也不相信所有真理都藏在某一种专业能力里。他说自己的生活是英语和数学的凸组合。他不但接受这一点,还希望自己的孩子也这样,左右脑同时开着。

文学化编程的核心动作,是让人通过至少两种视角去理解同一个复杂的东西:形式地看一遍,非形式地看一遍。好的技术作者不会把这一点做得太明显,但他会把同一件事说两遍、三遍,一遍正式,一遍口语,目的只有一个:让读者把这个概念放进自己的脑子。

他说,写作这件事,目标在读者。作者要心里有一个清晰的读者形象,说出读者下一步期待听到的话,把自己觉得有意思的地方,让读者也觉得有意思。

写程序也一样。你写的程序不只是给计算机下指令,它还要给将来维护这段代码的人、给正在调试它的自己,讲清楚「为什么要这么干」。老师讲课用的所有阐述技巧,只要你写的程序不是一次性用完就扔,都会让你成为更好的程序员。

Lex 问他,把形式和非形式结合起来有多难。克努特说,这个问题问他不见得合适,因为他是极客,这类事他做起来不难。但他也承认,有些人写东西就是困难,可能是大脑结构的关系,也可能只是练得不够。他不敢下判断说任何人都能学会。

他能确定的是:写作是他生命的一半。他把写作和编程放在一起。哪怕写一个只用一次的程序,他也会用文学化的方式写,因为这样他更快把它写对。

从 1962 年的目录说起

1962 年,克努特列了一份目录。他要写的书,主题是如何写编译器。那时候全世界写过编译器的人也就几十个,他恰好是其中之一。他还给校报写过稿,所以他觉得自己可以当那个记者,把别人那些绝妙的想法讲清楚。

结果目录越拉越长。他加了数据结构,因为编译器作者得在一张表里查变量;他加了搜索,因为编译器得判断两个地方出现的同名变量是不是同一个;他加了算术,加了他最喜欢的组合数学。原本第十二章才是编译器,前面十一章全是铺垫。

然后七十年代来了。组合数学领域发生了一次大爆发。他说,如果看 1975 年,计算机科学的期刊里超过一半都在讲组合方法。图论占主导,哈密顿路径、旅行商问题,从图论再往外走,是运筹学。运筹学当年只管那些有高效解的小问题,通常跟拟阵(matroid)这种特殊的数学结构有关。可一旦问题从「两个两个地看」变成「三个三个地看」,难度就变了。二元的可满足性问题可以在线性时间里判定,三元的可满足性问题,到今天也没人知道怎么做。

这本原本打算写十二个月的书,变成了七卷本的大工程。今天他写到第四卷 B 分册。有人问他能不能用一部电梯的时间概括这套书,他说,那得看这栋楼有几层。

第一卷《基本算法》,讲的是你绕不开的东西:什么是程序,什么是算法,一台低层机器长什么样,输入输出、子程序、归纳法、数学预备知识。这本书和别的书不一样的地方在于,他不光给出算法,还要定量地分析它。他要回答的是「它工作得有多快」,「它能工作」只是起点。所以他需要数学。

第二卷《半数值算法》,讲的是针对数字的算法。浮点算术、高精度算术、矩阵、随机数、幂级数,计算机怎么理解算术。

第三卷《排序与查找》,他自己最喜欢的一卷。这里处理的未必是数字,也可以是字母、是任何可以比较的对象。他特别提到,现在大家天天用 Google,本质上还是在找东西。

第四卷《组合算法》,是「无数问题」的领域。这里他不断遇到这样的情况:一个好想法可以让某个算法快一百万倍以上。也有一堆问题可能永远不会有高效解法。放弃依然没有理由,你还有机会想出好点子,跑得更快。

「组合算法是我一直最喜欢的,因为我的编程技能在这里回报最大。一个显而易见的算法,和你后来想到的那个不那么明显、但能把前者远远甩在后面的算法,差距就在这里。计算机科学真正发挥作用的地方也在这里。」(唐纳德·克努特)

那张椅子,那沓纸,和七天的节奏

Lex 问他每天的写作流程。克努特说,这大概是最好的问题,因为他一周七天都在做这件事。

他坐在一把椅子上,那把椅子是瑞典人设计的,是唯一一把他能连续坐几个小时、坐到忘记自己坐在椅子上的椅子。旁边有一张立式办公桌。他的流程是:先用铅笔在纸上写,然后站起来,打字,修改,重写。

他拿出一沓纸给 Lex 看。那是他四十年前在加拿大看望姐姐时买的,尺寸很大,行距很小,刚好适合他。他保存着从六十年代开始的全部手稿。他打字很快,高中上过打字学校,打字速度比思考速度还快。所以当他把纸上的东西打到屏幕上时,风格和节奏会在打字的速度里自然长出来。

Lex 问他会不会用宏,会不会用 LaTeX 那种思维方式写东西。他说需要宏的时候会用,但他并不依靠宏来思考。他还说,他会为了版面改句子。如果换一种说法能省下一行,他会换,像写俳句一样,把句子重写到在页面上更好看为止。他说这大概只占他百分之三的时间,他不该在这上面耗,可他忍不住。

Lex 说,也可以说生活就是这样。克努特说,确实。他每周花一天在花园里,他的生活就是除草、抓虫,只不过对象换成了程序。

他说,乐趣出现在什么时候?出现在你能把两个人的想法拼到一起,而这两个人彼此不知道对方的工作,你可能是第一个同时看到两边的想法的人。那一刻你有机会做综合,那就是创造。

苦役出现在什么时候?出现在你得把每件事追到根上。追根会把你带进奇怪的地方,比如他为了写书去学了梵文。他给每个作者写感谢信,作者去世了,就写信给认识作者的人。他要把数学弄对。读者会拿着他的程序找漏洞,他得一遍遍重写。

有没有白费功夫的时候?有。他曾经花了很长时间准备一个以棒球为主题的大型例子,甚至打算做折叠插图。后来他想,一个从小打板球长大的人会怎么看?一个从小踢足球长大的人会怎么看?他在这个例子里到底在教什么算法?他把整个例子删了。后来连保龄球的例子也删了,因为那更小众。

为什么叫「艺术」

《计算机程序设计艺术》这个书名里,「艺术」这个词是克努特专门想过、还在图灵奖演讲里讲过的。

他说,art 这个词的本义是「非自然之物」,和 artificial intelligence 里的 artificial 同一个词根,意思是人创造出来的东西。后来这个词引申出「美术」的意思,带上了美的维度,意味着一样东西不但是人造的,而且做得优雅,带来愉悦。

所以当他说「程序设计的艺术」,他想说的是:你写一个程序,可以把它写成一件作品。

「艺术是人类特别擅长的那部分东西。当人们说人工智能的时候,他们是在试图模仿人类。但这里面有一个美的、优雅的成分。这也是我一直想说的:你可以写一个程序,把它写成一件艺术品。」(唐纳德·克努特)

1986 年的一个意外

Lex 问他,有没有哪个想法彻底改变了他看问题的方式。

克努特说,他每次程序出 bug 都会「惊讶」,但那不是他说的那种惊讶。他讲了一个具体的例子。

BDD,二元决策图(binary decision diagram)。它是 Randy Bryant 在 1986 年提出的结构。克努特说自己从五十年代就开始编程,是老家伙了,他以为布尔函数这种东西早就被研究透了。命题逻辑是一切的基础,我们知道的几乎所有东西都能用它描述,他以为这块地已经耕完了。

结果 1986 年来了个全新的想法,彻底改变了布尔函数的表示方式。到九十年代,它成了设计计算机芯片的标准方法,直到 2000 年 SAT 求解器崛起才被取代。

这件事直接改变了第四卷的结构。第四卷 B 分册中间三分之一,三百多页,讲的全是这个东西,其中大部分材料是本世纪才发现的。他得从零开始,去见这个领域里的人,写了十五套不同的程序,书里描述了其中七套,另外八套是给他自己理解问题用的。

还有一个小插曲。BDD 火了之后,理论研究者开始研究它「做不到什么」,于是它名声变差,因为它不能解决所有问题。克努特说他预计,接下来十年,理论研究者会证明机器学习也解决不了所有问题。

他自己不怎么担心最坏情况。他的快感来自「这个问题我以前解决不了,现在能解决了」,哪怕这个问题本身又引出了下一个问题。他知道自己比以前强了,这就够了。

P 是不是等于 NP,以及那些「知道存在却不知道长什么样」的算法

克努特反复讲过同一个直觉:他倾向于认为 P = NP,但即便有人证明了 P = NP,也不会直接给你一个能解决实际问题的算法。

他的理由很直接。存在的算法,比任何人能理解的、能发现的算法都要多得多。我们现在的处境是:我们知道某个算法存在,却一点头绪都没有,不知道它是什么。

他举了两个例子。

第一个是 Hex 游戏。黑白双方轮流在六边形格子上放石子,白方要从左连到右,黑方要从下连到上,没有吃子,没有和棋。游戏有限,不存在平局,所以一定是先手必胜或后手必胜。数学上可以证明先手必胜,用配对策略可以推出后手不可能赢,但我们不知道那条必胜之路该怎么走,也不知道先手第一步该下哪里。

第二个是图论里的 Robertson-Seymour 定理。它说,任何一个在取子式下封闭(closed under taking minors)的图类,都存在一个多项式时间的算法,判断一个给定的图是否属于这个类。取子式的意思是,你可以把一条边缩成一个点,也可以删掉一条边,得到的新图还留在这个类里。

这个定理证明了:每一个这样的图类,都存在有限个「最小的坏图」,一个图不属于这个类,当且仅当它包含其中一个坏图作为子式。既然坏图是有限的,那就可以逐个测试,每个测试都是多项式时间,加起来还是多项式时间。

「于是就有了一个多项式时间算法,可我们并不知道它长什么样。我们只知道坏图的数量是有限的,我们可能只知道其中一两个,不知道到底有二十一个还是二十五个。我们只知道它有限。」(唐纳德·克努特)

Lex 说,这就是你觉得 P = NP 可能也没用的原因。克努特说,差不多。你要排除的可能性太多了。他讲了一个头发数的类比:一个国家的人口数远小于一个人头上的头发数,那么必然有两个人头发数一样多。这里面没有巧合,起作用的是抽屉原理。组合算法的世界里,这种因为可能性太多而撞上的事情经常发生。

他说,有人反驳他:如果 P = NP,那么多聪明人研究这么多年,还有百万美元悬赏,怎么就没找到?克努特说,他可以用完全一样的逻辑反过来说:那么多聪明人努力证明 P ≠ NP,也都失败了。这个逻辑两边都能用,说明它撑不起一个证明。

最后他把话题拐到了外星人。Lex 问,你觉得宇宙里有智慧生命吗?克努特说,他不知道,也不花时间想。他不愿把时间花在自己永远无法知道答案的问题上。但他又说,他很高兴有些问题没有答案,因为有了答案,谜就没了,世界就太无趣了。

蚂蚁、生命游戏,和「假装理解」的界限

Lex 提到,克努特说过,理解蚁群如何完成高度组织化的任务,可能是理解人类认知的关键。蚁群是个分布式系统,而每一只蚂蚁在干什么,我们看得见。

克努特说,对,这就是蚁群的优势。我们知道哪只蚂蚁在跟哪只蚂蚁交流,大脑内部就难得多,你不知道神经元之间传递信号到了什么程度。他倾向于把蚁群当成一个单一的认知体,而不是一堆蚂蚁的集合。就像大脑里的细胞、还有微生物组,都是互相作用的实体,但他把自己当成一个人。

Lex 又问到康威的生命游戏(Conway's Game of Life)。克努特说,生命游戏能模拟任何可计算过程,可这不是它最强大的地方。它的魔力在于规则极度简单、单元极度分散。我们能完全看清它的原语是什么。这仍然不意味着他理解了「生命」。

它给他的是一个视角:一个确定性的宇宙意味着什么,自由选择对我们意味着什么。

Lex 问,你觉得上帝掷骰子吗?克努特说,掷。他不觉得有理由禁止上帝使用最高效的方法,而我们知道随机性对很多算法来说是必需的,有些事情不靠随机就做不好。

圣经、随机抽样,和「更接近」

1999 年,克努特在 MIT 做过一系列关于宗教和科学的讲座,后来结集出版。他在书里讲了一个方法论:面对一个复杂到超出人类理解的主题,你怎么办?

他的答案是:随机抽样。不要只研究别人让你研究的那部分,也不要因为太难就什么都不研究。挑一个在你能力范围内的随机子集,深入进去。

他给自己定了一个子集:大概三千节经文里的六十节,比例约五百分之一。然后他去图书馆,波士顿公共图书馆每周去一次,去了一年;哈佛的图书馆也去过几次。那里的索引做得很好,他可以直接翻到某本书的某一页,看这一节经文有没有被提到。这样他不光学了圣经本身,还学了关于圣经的二手文献,那些学者写了什么。

「这给了我一些坚固的钉子,可以把零碎的信息挂上去。但我不会说,因此这就是真的。这只是一种随机抽样的方式。」(唐纳德·克努特)

他读出来的核心是什么?他说,要点不在大多数人以为的那些戒律,而在如何与上帝的意愿和谐共处。他假设上帝存在。他说他很庆幸这件事无法被证明,因为如果能证明,他看一遍证明,记住,然后就完了,他不会再对精神性的东西、对谜感兴趣,他的人生会非常不完整。

他还提到他研究过的一节经文,可以解读为:做一个无神论者,也比什么都不在乎要好。

Lex 问他,如果你是上帝,你会怎么向地球上的人显现自己?克努特提到一本小说,他忘了是不是叫《Blasphemy》,讲的是上帝在洛斯阿拉莫斯通过一台计算机显现自己。他说那是他读过的唯一一本把点睛之笔放在最后一个词、而且最后一个词解释了整本书的书。他不想剧透,但那本书恰好就在谈这个问题。

他说,如果上帝觉得过去跟世界沟通的方式不适合 21 世纪,那会怎么做?也许就是那本书里写的方式。

他还说,做这个思想实验,大部分时候你会学到的是谦卑。解出一个问题,不代表其他问题会跟着掉出来。你得意识到有些东西超出你的能力。

Lex 说,我看到周围全是傲慢(hubris)。克努特说,说得对。

0.8 是够的

Lex 让克努特对自己的人生做一次程序分析:正确性怎么样,运行时间怎么样,渐近意义下的资源使用怎么样。

克努特说,这个问题以前没人问过他。他说他一开始装的是库、子程序,学着做一个听话的自动机。他有一个巨大的优势:他没有可以责怪的人。如果他有什么没搞懂,他知道该停止打乒乓,那是他自己的错,是他没努力学,并没有谁在歧视他。他说他不知道怎么消除世界上的偏见,但他知道自己不必承受那份额外的负担。

后来他从父母那里学到了利他,学到了服务他人更重要。再后来他意识到,自己得先足够快乐,才能去服务别人。

最后他给这套人生哲学起了个名字:「0.8 就够了」。

「如果我能给幸福打分,我觉得一个生物体快乐百分之八十的时间,这是好设计。如果百分之百快乐,那就像所有人都在嗑药,什么都干不成,整个系统会崩掉。」(唐纳德·克努特)

他承认自己也会有低落的时候。他说他知道那是被「编程」成这样的,如果情绪失调、比该有的更沮丧,他会试着想:今天该生谁的气?然后他意识到,那只是化学反应在告诉他应该生气。他说,那我就把它放一边,去睡觉,会好起来的。不百分百快乐,不意味着他要去街上找个人吼一顿。他可以接受自己足够快乐,能够成为可持续状态的一部分。

2006 年,和一场死亡预习

2006 年,克努特被诊断出前列腺癌。Lex 问他,这次跟死亡的照面有没有改变他看世界的方式。

他说,有。他第一次真正面对死亡,是父亲去世的时候。他花了一个月,才慢慢接受自己总有一天也会死。那一个月里,他觉得自己还行,可他唱不了歌,也做不了原创研究。他记得大概三四周之后,他第一次冒出一个有意义、稍微有点创造性的技术想法,他能感觉到某个东西又开始动了。在那之前,他觉得很空。

后来他知道,哀伤有一个标准的过程,他走的就是这条路。

2006 年被诊断的时候,他的反应很平静。他想,我这辈子运气一直很好,没什么可抱怨的,也许现在就到此为止。他没有觉得自己理应得到更好的结果,也没有为未来做计划。他做了手术,术后重新学走路,疼了一阵子,然后回家了。回家之后他才意识到,他根本没想过接下来要干什么。他心里没给自己留什么期待,只冒出一句:哦,我还活着,那我还能再写几本书。

他说,那种「这太不公平了」的情绪,他心里没有。他接受结果。他说,他已经拿到了超过自己份额的东西。

访谈里他还提到另一件未了的心愿:写一部音乐作品。他脑子里有一个想法,觉得某种音乐应该被写出来,至少得有人试一试。他知道不容易,可他想做一个概念验证,想知道这条路走不走得通。他花了很多时间,最终完成了。去年他八十岁生日,这部作品做了世界首演,后来在加拿大又演了一次,据说欧洲也在谈演出。

他说,那件事做完了,它现在是世界音乐的一部分,好也罢坏也罢,他做了他想做的。

现在他日程上只剩一件事:《计算机程序设计艺术》,尽他所能写到终点。

Lex 问,会不会有一个「1.0」的时刻?克努特说,他更愿意把它看成:那场音乐会结束时,他其实已经触到了 1.0。2006 年他处在 0.8,被诊断出癌症时他想,也许这就是终点了,结果没有。他接受了任何结果。

两根「2」的战争

如果说克努特在什么事上追求过 0.98,那就是排版。

七十年代,他创造了 TeX 排版系统,配套的 METAFONT 语言用来描述字形,还有 Computer Modern 字体家族。今天,数学、物理、计算机科学以及大量工程领域的论文,用的还是这套东西。

Lex 问他,美很难量化,你怎么创造出美的字母和美的公式?

克努特提到哈佛数学家 George David Birkhoff 在三十年代写过一本《Aesthetic Measure》,书里印着花瓶的图片,每张图下面标一个数字,代表这个花瓶多美。Birkhoff 还写过音乐,克努特一度想过,能不能在作曲时把他的算法编成程序,让作品拿到他评分体系里的最高分。他说,那套东西不够严谨,计算机做不了。可那是人们给美赋值最认真的一次尝试。

格什温的老师也写过两卷本,讲他的作曲方法。Lex 想问的却是另一种美,字母的美,线条和曲线的美。

克努特说,那就在观者眼里。你只能尽力靠近你心里那个美的定义,尽可能靠近。

他说,他的定义很私人:它得让他自己满意。这就是标准。这个标准曾经让他非常痛苦。

《计算机程序设计艺术》第二卷出新版的时候,他以为那会是他人生中最快乐

的一天。结果他打开书,看到同一个封面、同样的装帧,可页面上的东西不好看。那个「2」特别丑,他受不了。任何一个画家都会把页码上的「2」画好。他做了很多测量,用不同的方式看,技术是好的,可他还没做完。1961 年之后的所有东西,他都得重新写。

Lex 问,它最终让你满意了吗?克努特说,当然。他说,那么多书是因为这套系统才写得出来。而且现在他坐在书房里,看到上面那些排好的页面,如果他不喜欢,他随时可以改。别人没有这个能力,他们只能用他给的东西。

Lex 又问到间距、留白,能不能更系统一点?克努特说,你永远可以再往前走一步。他说他在排版上并没有停在 0.8,他大概是从 0.98 开始的。

Lex 说,这好像违背了你自己的幸福法则。克努特说,这里不一样。日本有一种美学叫侘寂(wabi sabi),认为最美的作品是那些带瑕疵的,因为观者可以在瑕疵里加入自己的欣赏,这会带来更多满足感。排版上他要的东西恰好相反,他要的是绝大多数情况下都尽可能好看。做不到的时候,他就说:好吧,作者得多花百分之二的工作量。

他不肯把「做到百分百」当成自己的任务,那会把作者的所有工作都抢走。这就是他说的「0.8 就够了」的意思。

我们对宇宙的理解,是一个极小的数

访谈快结束时,Lex 让克努特估一个数:人类对现实本质的理解,占多少?

克努特说,无穷小。小数点后面不知道多少个零。

他说,数学家办公室里坐他隔壁的那些人,从来不考虑比可数无穷更小的东西,而他几乎不碰无穷,因为他处理的都是有限的东西。可即便只谈有限,宇宙可能只是有限个夸克组成的,而所有人类能理解的数,仍然远远小于几乎所有的有限数。

他提到自己写过一篇论文叫《Supernatural Numbers》,讲的是康威箭头表示法(Conway chained arrow notation)。规则说穿了不复杂:没有箭头是乘法,一个箭头是指数,两个箭头是把指数反复迭代,三个、四个箭头往上叠,数字会膨胀到完全无法想象。

他举的例子是 10 加四个箭头再加一个 3。先算 10 的三重箭头,那已经是一摞指数塔,塔有多高你都说不清。算完这一遍,只完成三重箭头,还得再来一遍才到四重箭头。这个数早已超出任何人的想象。

可它和真正的有限数比起来,还是小得可怜。克努特说,他不过是用了 10、3、4 这几个小小的参数。你要是把箭头的数量本身设成那个超大的数,那才是有限数真实的样子。

「有限与无限之间的那条界线,对人类来说本身就是不可理解的。」(唐纳德·克努特)

无穷是一个好用的工具,它帮我们思考那些极大的东西,我们甚至能对它做运算。我们永远无法确知,这个宇宙是否真的接近过它。

所以克努特说他清楚自己知道得多么少。紧接着他又补了一句:即便在这么小的宇宙里,人类确实发现了很多东西,多到任何一个人都装不下。「我们干得还不错。」这是他的原话。

见上帝时,他会问什么

访谈最后,Lex 抛出了一个常见的问题:你上了天堂,见到上帝,能问一个问题,而且一定会得到回答,你会问什么?

克努特的回答是:「你这儿的浏览器是哪个?」

Lex 说,这答案真美。克努特接着说,他其实不觉得这是个有意义的问题,可他真心希望那儿网速够好。

这个回答里包含了他对终极问题的整套态度。前面他已经说过一遍:他不花时间思考那些自己永远不可能知道答案的问题。他不否认神秘的价值,他甚至希望有些谜永远不要被解开,因为一旦解开,世界就太无趣了。珍视神秘和沉迷于猜测是两件事,他把这两件事分得很清楚。

所以当被问及上帝、宇宙、外星文明时,他的答案永远分成两层:一层是「我不知道,我也不打算猜」;另一层是「这个问题本身很好,它让我保持谦卑」。

他怕的是误以为自己已经对了

把这些片段串起来看,会发现克努特的整套思维方式有一条主线。

他对人工智能的态度就是一个例子。他说,AI 社区从六十年代起就是计算机科学最大的灵感来源,可能超过任何其他群体。他们总去啃「智能最了不起的那些成就」,逼着整个领域把边界往外推,也因此产生了一大批好问题,以及越来越多成功的答案。

他真正担心的,是人们在还没做到的时候就开始相信自己已经做到了。

「让我不安的是,当人们开始相信自己真的成功了。因为在我看来,真正理解一样东西,和能够假装理解、能够制造出理解的错觉,这中间有一道巨大的鸿沟。」(唐纳德·克努特)

Lex 追问:你觉得可以在不理解的情况下创造出东西吗?克努特说,他天天这么干,他喜欢用随机数。可那道鸿沟还在那儿。他说,他不敢断言真正意义上的智能不可能被造出来,他只是没看到任何东西在靠近他心里那个标准。

注意他用的词:他心里那个标准。他不把自己的标准当成客观真理往外推,可他也不因为别人都说「快成了」就跟着改口。

同样的克制出现在他对 P/NP 的判断里。他说自己倾向于 P = NP,紧接着补一句「这绝不是证明」。他说他也可以用同样的逻辑推出相反的结论,说完就承认这个逻辑撑不住。

这种「先给出判断,再自己拆掉论证的地基」的说话方式,在整场访谈里反复出现,跟故作谦虚没什么关系。这是长期训练出来的思维习惯:把结论和支撑结论的论证分开存放,论证不够硬的时候,结论就只能停在「直觉」那一格,不能往上挪。

非一致性,才是他真正的主题

如果只记住这场对话里的一件事,那应该是克努特关于「非一致性」的那段话。

他说,很多纯数学建立在一条或两条普遍规则上,从规则出发,一切都能推演出来。而像他这样的人,可以跟一个有十个步骤、每步干一件不同事情的算法和平共处,不觉得难受。他甚至承认,正因为如此,他们有时候会造出比必要的更复杂的系统,因为他们不觉得「没找到那条简单规则」是件大事。

这套哲学解释了他几乎所有的选择。

他的书里为什么混着高层和低层?因为他能在层级之间跳,跳起来不费劲。

一个形式化大师为什么会发明文学化编程?因为他不相信一种尺寸适合所有人,也不相信所有真理都藏在同一种专业能力里。

他为什么愿意花一个月吸收四个日本研究者提出的新想法,把旧方法在几十个老问题上重新跑一遍,再写最终稿?因为他享受的是把两拨互不相识的人的想法接上。

他为什么能接受自己只快乐八成?因为一个百分之百运转的系统,在他看来就是设计失败的。

「0.8 就够了」在他这里有一层工程学的底子。他做排版做到 0.98,因为那是他能控制的、能一遍遍重来的东西;他对幸福只要求 0.8,因为那里面有一半变量不在他手上。

他分得清哪些事该追到极致,哪些事该放自己一马。

一个不查邮件的人,是怎么把书写完的

Lex 在开场提到,为了约到这次访谈,他得想别的办法,因为克努特不查邮件。

这件事放在整场访谈里看,一点都不奇怪。克努特描述的工作方式是这样的:铅笔、纸、一把能坐几个小时的椅子、每天站起来打字、一周七天、每周写五个左右的文学化程序。他保存着从六十年代起的所有手稿。他去图书馆翻纸质索引,一页一页查某节经文有没有被学者讨论过。他给作者本人或作者的熟人写信。

每一个环节都需要长时间不被打断的注意力。收件箱是这种注意力最大的敌人,它每天把几十件别人认为重要的事塞到你面前,让你以为自己在处理事务,其实你在被别人安排。

他不查邮件,跟清高没什么关系,他在保护那条唯一能产出东西的时间线。他今年八十多岁,还在写第四卷 B 分册,还在给一本书追加上百页的新材料。这套工作方式显然有效。

访谈里有一个细节。Lex 问他:写书这么多年,有没有想过降低标准,别什么都试一遍,直接把答案报出来就完了?克努特说他确实这么想过,很多天都在想,为什么我非得有这么高的标准。然后他咬牙做完,乐趣会在看到好结果的时候出来。更大的乐趣,是看到有人真的读懂了他写的东西,并且告诉他怎么改得更好。

这就是他愿意继续坐下去的原因。这里没有抽象的目标,只有具体的、来自真实读者的回声。

铅笔、纸,和一种正在消失的耐心

这期访谈里有一个不太起眼的细节,值得单独拿出来说。克努特描述写作流程时,把顺序讲得很清楚:先在纸上写,用铅笔和橡皮,写完了站起来,打到机器里,然后改。

纸上的那一遍,是想法第一次变成形状的过程。打字的那一遍,是形状第一次接受检验的过程。他说他打字速度快过思考速度,所以风格和节奏会在打字的时候自己长出来,出来的东西跟纸上已经很不一样。

这两遍不能合并。今天大多数人的工作方式是直接在编辑器里从第一句话开始写,边写边改边删,一个下午过去,屏幕上的字数和早上差不多。那种写法的毛病在于,思考、表达和评判同时进行,三个动作互相打断。

克努特的流程把这三件事分开了:纸上只管想,键盘前只管说,改稿时再只管评。

他还提到一件更小的事:为了版面改句子,为了省下一行重写整句,像写俳句一样。他说这大概只占百分之三的时间,不该浪费,可他忍不住。

这百分之三,恰恰是他身上最难复制的那部分。一台机器可以检查语法、检查拼写、检查代码能不能跑,它检查不出「这句话在这个页面上不够好看」。能够对这种事产生不适感,是一个人长期跟自己较劲之后留下的印记。

他给世界留下的东西,没有一个是他计划中的副产品

这场访谈里有一个反复出现的模式,值得单拎出来。

他想写一本编译器的小册子,结果写出了七卷本的《计算机程序设计艺术》。他为了让自己的书排版好看,造了 TeX,结果整个数学、物理、计算机科学界的论文排版都靠它。他发明文学化编程,初衷只是让自己写程序时更快写对,结果成了一种影响深远的编程观念。

每一次,起点都是一个具体到不能再具体的问题:这本书怎么排才好看,这段代码怎么组织我才不出错,这个例子到底在教什么算法。每一次,终点都远超他当初的设想。

这跟很多人的直觉相反。大家以为要做大事得先有宏大的规划,得先想清楚十年后要成为什么。克努特的路径是:先把手头这一小块做到别人做不到的程度,然后那一小块自己会往外长。

Te X 能统治学界几十年,不因为他规划了一个排版帝国。是因为他真的无法忍受页码上一个丑陋的「2」,然后一路追下去,追出了一整套字体、一整套排版算法、一整套描述字形的语言。这条路的每一站都由「还不够好」推着走,没有一站来自「市场需要什么」。

一个想法能长多大,取决于推它的人愿意追多深。

它变成你自己的东西

克努特在这场访谈里给出的,是一组可以今天就用起来的动作。挑一两个开始,比全部收藏起来更有用。

  • 给自己设一条 0.8 的幸福线。接受自己有一部分时间状态不好,那段时间别逼自己产出,也别去找一个人来承担这份情绪。睡一觉,等化学反应过去。
  • 分清「能反复重来的 0.98」和「不在你手上的 0.8」。排版、代码风格、文档质量这类可以一次次改的东西,值得追到近乎完美;行业走向、别人的评价、身体的衰老,追到八成半就该停手。
  • 每次写代码时问一句「三个月后我还看得懂吗」。看不懂就补上那段「为什么要这么干」的说明。这是文学化编程最小可行的版本,不需要任何工具。
  • 遇到复杂到超出你理解的东西,随机抽一小块,钻到底。不要因为整个主题太难就什么都不学,也不要只学别人指定的那部分。挑一个在你能力范围内的子集,去原始文献里把它挖穿。
  • 把想、说、评三个动作分开。先用纸把想法写成形状,再打字让它接受检验,最后才回头评判。别在同一个屏幕里同时干这三件事。
  • 给深度工作留出整块时间,别让收件箱把它切碎。克努特的做法极端,方向是对的:一天里至少有几个小时,别人找不到你,你也不主动找别人。
  • 把结论和论证分开记。写下你的直觉判断,同时标注支撑它的理由有多硬。理由不够硬时,让它停在「直觉」那一格,别急着对外宣布成结论。
  • 去找那个能把你两个领域的想法接起来的问题。克努特说,创造发生在你成为第一个同时看到 A 和 B 的人的那一刻。你在两个圈子里都待过,那就是你独有的位置。
  • 先把手头那一小块做到别人做不到,别忙着规划全局。TeX 是从一个丑陋的页码「2」长出来的,不是从一个排版帝国的蓝图长出来的。你现在抱怨得最厉害的那个细节,往往就是入口。
  • 写完东西,想办法让真正读懂它的人给你反馈。他说最大的快乐来自有人读懂了,并且告诉他怎么改得更好。找这样的人,比找一百个点赞有用。

访谈的结尾,Lex 引用了克努特的一句话:我们应该持续努力,把每一门艺术转化为科学,而在这个过程中,我们把艺术本身往前推了一步。

这句话放在克努特自己身上最合适。他把排版从手艺变成了可以计算的东西,然后在计算之上重新做出了艺术。他把写程序从技术变成了可以阅读的文章,然后在可读性之上让程序有了被理解的可能。他甚至把自己的人生当成一个可以分析的算法来审视,最后得出的结论是:八成,够了。

一个不查邮件、用铅笔写程序、八十岁还在改稿的人,比谁都清楚两件事的分量:长时间不被打断的注意力,以及在没人监督的时候,仍然愿意把 i 上那一点、t 上那一横画好的那点倔强。前一件决定你能走多远,后一件决定你走过的地方留下什么。

本集资源与出处