39

原文见 http://bartoszmilewski.com/20...

我打算为程序猿们写一本讲范畴论的书已经有一段时间了。注意,受众不是计算机科学家,而是程序猿——是工程师,而不是科学家。这听起来挺疯狂,我也有些诚惶诚恐,但是我无法容忍科学与工程之间存在着巨大的鸿沟,更何况我自身的工作也是经常需要我在这两个世界中穿梭。不过,要解释一些东西,总让我感觉非常窘迫。我非常敬仰 Richard Feynman(理查德·费恩曼),在讲授知识方面他是深入浅出的大师。我不是 Feynman,但我会尽力。我从发布这篇序言开始,激励读者学习范畴论,希望能引发一些讨论并得到一些反馈意见。

下面我要用几段文字让你相信,这本书是写给你的。根本没必要担心它是几乎会耗尽你所有的业余时间的一门最抽象的数学。

我的乐观来自一些观察。首先,范畴论是相当有用的编程思想宝藏。Haskell 程序猿们已经涉足此境很久了,其中的一些思想正慢慢的渗入其他语言,只是这一过程是非常缓慢而已,我们需要使之加速。

其次,有许多种数学,它们面向不同受众。你可能不喜欢代数学,但这并不意味这你无法喜欢范畴论。我会向你展示,范畴论非常适合程序猿的思维。因为范畴论处理的对象不是计算细节,而是结构。它处理的是使程序可复合的结构。

复合是范畴论的精髓,它也是范畴论自身定义的一部分。我会证明编程的本质是『复合』。我们一直都在组合一些东西,这种行为从很久以前一群伟大的工程师提出子程序的时代就开始了。很久以前,结构化编程原理掀起了编程的革命,它立足于代码级别的复合。伴随面向对象编程而来的则是对象的复合。函数式编程不仅仅设计函数的复合与代数数据结构,它还提供了对并发计算的支持,这是其他编程范式难以实现的。

第三,我有秘密武器,一把庖丁之刀,我要用它将数学大卸八块使之成为程序猿的美味佳肴。如果你是数学家,你不得不大胆假设,小心求证,严格的构造你的定理,然后产生令外人难以卒读的论文与专著。我是训练有素的物理学家,在物理学中,我们使用着并不正规的推理来取得令人激动的发现。数学家们嘲笑伟大的物理学家 P. A. M. Dirac 为求解一些微分方程而提出的狄拉克 δ 函数,但是当他们发现了一个叫做广义函数论的新的数学分支时,他们就不笑了,因为广义函数论只是对 Dirac 观点的一种形式化描述。

当然,采用不严肃的论证方式很容易产生谬论。因此在这本书中凡是遇到不正式的论证时我会尽力确定其背后存在着相应的实际数学理论。我床头有一本被我翻的破破烂烂的 Saunders Mac Lane 写的《Category Theory for the Working Mathematician》。

译注:Category Theory for the Working Mathematician,可翻译为『面向一线数学家的范畴论』?

由于这本书是写给程序猿的范畴论,因此我将会用计算机程序代码展现范畴论的主要概念。你可能会担心函数式语言会比传统的命令式语言更接近数学,并认为前者为此已经提供了更多的抽象能力,所以想当然的认为只有学习了 Haskell 方能将范畴论的能量作用于现实,或者认为范畴论在函数式编程范式之外没有什么用处,这些看法并不正确。我会提供大量的 C++ 的例子,只不过你得容忍一些丑陋的语法,需要在繁琐的代码中探寻清晰的模式,并且在更高层抽象的场合不得不做一些复制与粘贴的工作,不过这也正是大部分 C++ 程序员经常干的事。

不过,你也无法脱离 Haskell 的羁绊。虽然没有必要成为一名 Haskell 程序猿,但你需要将 Haskell 作为一种草图性的语言,用于描述那些 C++ 示例的实现思想。这也正是我当初开始学习 Haskell 的所用的方法。Haskell 简洁扼要的语法与强大的类型系统,对于理解与实现 C++ 模板、数据结构与算法非常有帮助。当然,我不可能要求读者事先以已经了解 Haskell,我会逐步介绍 Haskell 的知识,并且会对我所用到的那部分 Haskell 代码给出详细的解释。

如果你是一名有经验的程序员,可能会自问:即使不懂范畴论与函数式方法,我也照样写代码,似乎没什么必要学习它们。的确如此,不过你无法阻止正在侵入命令式语言的那股沉稳的函数式潮流。即使是 Java,面向对象编程的坚固堡垒,也拱手请来了 Lambda。C++ 也正在大踏步前进,现在每隔三五年就发布一个新标准,它正在尝试赶上这个正在变化的世界。这一切都在为一场变革而准备,这种变革,用我们物理学家的术语可称为相变。如果你持续的烧水,它最终会沸腾。我们现在正处于青蛙的位置,必须决定是在升温的水中继续游动,还是开始作出其他抉择。

热水中的青蛙

驱动编程范式产生巨大变革的力量之一是多核革命。主流的编程范式——面向对象编程已经难以胜任并发与并行计算领域,它只会造成危险且充满 bug 的设计。数据隐藏,是面向对象的基本前提,一旦对象被共享且被修改,就会造成数据竞争。将数据与互斥锁组合起来看似是个不错的解决方案,但不幸的是,互斥锁不能组合,并且一旦在数据竞争中出现死锁,程序非常难以调试。

对于非并发计算,软件系统日益递增的复杂度也正在炙烤着命令式编程范式。简而言之,副作用正在失去控制。有副作用的函数很便捷又易于编写。原则上,有副作用的函数所产生的影响可在函数名以及注释中予以标明。一个叫做 SetPasswordWriteFile 的函数显然在修改某种状态并产生副作用,对此我们已经非常习惯且不以为然。只有当我们开始将这些有副作用的函数层层组装到一起,事情才开始变得棘手。副作用本身并不坏,但是将它们塞到一个大尺度视图中,我们很难再看清它们,它们便脱离了我们的掌控。完全与副作用打交道的命令式编程范式才是元凶。

硬件的变化与软件复杂度的增长都在迫使我们重新思考编程的根本思想。正如欧洲最宏伟的哥特式大教堂的建造者那样,我们正在面对着原料与结构的限制而磨砺着我们的技艺。法国的博韦有一座未完工的哥特式教堂,它就是人类与限制作斗争的见证。这座教堂的设计企图在高度与采光方面击败所有的教堂,但是建造中却出现了一系列的崩塌。当时不得不用钢梁木柱临时做成支撑架构来阻止崩塌,但于事无补,因为很多东西在设计上就是错的。从现代的视角来看,博韦教堂是个奇迹,其相当多的一部分哥特式结构已经成功的建造了出来,这在那个没有现代材料科学、计算机建模、有限元分析甚至没有普通的数学与物理的时代显得有些不可思议。我期望我们的后代也会敬佩我们在构建复杂的操作系统、网络服务器以及互联网架构中展现出来的技术。毫不客气的说,他们理应如此,因为我们是在脆弱的理论基础上完成的这一切。但是,如果我们想继续前进,那么就必须修正现有的理论基础。

博韦教堂用于阻止崩塌的临时架构

下一篇 -> 范畴:复合的本质


garfileo
6k 声望1.9k 粉丝

这里可能不会再更新了。


引用和评论

0 条评论