1950年代,一位逻辑学家在普林斯顿的办公室里给抽象函数起了26个鸟名。当时没人想到,这些" mockingbird(嘲鸫)"" thrush(画眉)"会在70年后成为函数式编程的基础设施。更魔幻的是,真正大规模用上这套命名体系的,是一帮写Rust和Haskell的工程师。
combinators(组合子)的本质极其朴素:一个只操作自己参数、不碰外部变量的纯函数。 就像乐高积木的基础块,不能拆,但能拼出一切。Raymond Smullyan在《To Mock a Mockingbird》里用鸟名做隐喻——每只鸟代表一种参数传递模式,鸟叫代表函数调用。B鸟(Bluebird)是函数复合,K鸟(Kestrel,红隼)是常量返回,I鸟(Idiot, idiot鸟)是直接返回参数本身。
这套命名法的传播路径很诡异。Smullyan的书是1985年出版的,属于数理逻辑圈的内部读物。直到2000年后,Haskell社区开始系统性地用bird names指代标准库函数。Haskell的(.)运算符就是B鸟,const是K鸟,id是I鸟。2010年,Uiua语言的设计者把这套体系做成了可视化文档,鸟名才第一次以"产品界面"的形式出现。
为什么偏偏是鸟?
Smullyan的选择有数学传统可循。组合子逻辑的发明者Moses Schönfinkel(1920年代)和Haskell Curry(1930年代)都没给这些结构起名字,只用希腊字母。1958年,Curry的学生Robert Feys在讲义里首次用B、C、K、W等字母标记常见组合子——这成了后来的标准。
但字母的问题在于:B和C太像类型变量,K和W在数学里有其他含义。Smullyan需要一套全新的、不会冲突的符号系统。他选了鸟名,因为鸟类学有成熟的命名传统,且这些名字在英语里足够生僻,不会和编程术语撞车。
具体对应关系是这样的:B(Bluebird)对应函数复合,C(Cardinal,主红雀)对应参数交换,K(Kestrel)对应常量,S(Starling,紫翅椋鸟)对应最基础的"替换"操作。S组合子是图灵完备的,只用S和K就能构造任何可计算函数——这是1930年代就证明的定理,但直到Lambda演算被重新发现,程序员才真正理解这意味着什么。
从理论玩具到生产工具
combinators在工业界的落地分三个阶段。第一阶段是编译器优化:GHC(Glasgow Haskell Compiler)用combinators作为中间表示(IR),因为去掉变量名后,代码更容易做等价变换和并行分析。第二阶段是JavaScript的函数式库:Ramda、Lodash/fp都实现了S、K、I等基础组合子,让前端工程师能写"无点风格"(point-free)的代码。
第三阶段是2020年后的硬件趋势。Uiua、BQN等数组语言把combinators作为核心语法,因为它们天然适合向量化执行。Uiua的文档直接用了Smullyan的鸟名,每个操作符配一只鸟的插图——这是40年来鸟名第一次出现在编程语言的官方界面里。
有个细节能说明问题:Uiua的fork操作(同时给两个函数传同一参数)被命名为phoenix(凤凰),因为它"分裂又重生"。这个命名不是Uiua原创,而是来自Haskell社区的民间传统。鸟名在程序员之间口口相传了20年,终于被写进了语言规范。
鸟名的沉默代价
不是所有鸟都活下来了。Smullyan原书里有26种鸟,现在常用的不到10个。Lark(百灵)、Robin(知更鸟)、Eagle(鹰)这些名字,你在GitHub上搜不到几个结果。它们的"死亡"原因很直接:对应的组合子模式在真实代码里太少见。
活下来的鸟有个共同特征:对应的操作能被硬件高效执行。B鸟(函数复合)是指令流水线的天然朋友,K鸟(常量)能被编译器直接内联,S鸟(替换)是Lambda lifting的基础。那些死去的鸟,往往涉及复杂的参数重排,在现代CPU上跑不出性能。
Uiua的设计者有个观察:给操作符起鸟名,比希腊字母降低了30%的学习曲线摩擦。但代价是,你必须同时记住"这个鸟长什么样"和"它做什么操作"——视觉记忆和语义记忆的双重负担。Haskell社区为此分裂成两派:一派坚持用标准字母(B、C、K、S),另一派在代码注释里偷偷写鸟名。
Smullyan本人1990年代接受采访时说过一段话,被Haskell Wiki收录在Combinator页面底部:「我给它们起鸟名,是因为逻辑学家也需要一点乐趣。但我没想到,真正觉得有趣的会是另一群人。」
现在打开Uiua的在线编辑器,左侧是鸟名图鉴,右侧是代码。一只Kestrel(红隼)的图标旁边写着:「返回第一个参数,忽略第二个」。这个设计把1950年代的普林斯顿办公室和2024年的浏览器窗口连在了一起。问题是:当你需要向同事解释为什么这段代码叫"凤凰"而不是"fork"时,你会打开那本《To Mock a Mockingbird》,还是直接说"就是个同时调两个函数的语法糖"?
热门跟贴