Day 19 · 2026.07.11

范畴论入门

Category Theory — 别打开盒子看里面,看它和世界的连线
"范畴论是数学的数学——它不研究某个结构,而研究一切结构共有的骨架。" — 改写自 Saunders Mac Lane

范畴

Category · 关系先于对象
Foundations
直觉版

传统数学总在「打开盒子」:集合里装着哪些元素、群里有哪些运算。范畴论换了个视角——忘掉对象内部长什么样,只看对象之间的箭头,以及箭头怎么接龙。

一个范畴就三样东西:一堆点(对象)、一堆箭头(态射,$f:A\to B$)、一条接龙规则(能首尾相接的箭头可以复合成一支)。惊人的主张是:一个数学对象的全部性质,都能从「它周围的箭头」读出来——你根本不用打开盒子。这一步——把注意力从「东西是什么」搬到「东西之间怎么映射」——是范畴论的全部起点。

A B C f g g ∘ f(复合)
正式定义

范畴 $\mathcal{C}$ 由对象态射构成,每个态射 $f:A\to B$ 有明确的起点和终点,并满足三条:可复合——若 $f:A\to B$、$g:B\to C$,则存在 $g\circ f:A\to C$;结合律——$h\circ(g\circ f)=(h\circ g)\circ f$;有恒等——每个对象 $A$ 都有 $\mathrm{id}_A:A\to A$,接龙时不起作用。
眼熟吗?这三条正是的公理去掉「逆元」——事实上,一个群就是「只有一个对象、每支箭头都可逆」的范畴。

为什么美

把视角从「元素」移到「关系」,是数学的一次哥白尼式转向。集合与函数、群与同态、拓扑空间与连续映射、向量空间与线性映射——这些貌似互不相干的领域,全都是范畴。于是一个定理只要在范畴层面证一次,就在所有具体范畴里同时成立。范畴论因此被称作「数学的数学」:它研究的不是某个结构,而是一切结构共享的骨架。

应用

数据库的 schema 就是范畴(表是对象,外键是态射)——这是 David Spivak 把范畴论用于数据集成的基础。函数式编程里,类型是对象、函数是态射,范畴论直接塑造了 Haskell 的类型系统。物理学中,拓扑量子场论(TQFT)干脆被 Atiyah 定义成「从流形范畴到向量空间范畴的一个函子」。

一句话精华:要理解一个东西,别打开它,看它和世界的连线——结构藏在关系里,不在元素里。
思考题:如果两个对象与其余所有对象之间的「箭头模式」完全一致,它们还能被区分吗?(这正通向「万有性质」与「同构即相等」的思想。)

函子

Functor · 保结构的搬运工
Category Theory
直觉版

范畴是一张「点 + 箭头」的网。函子就是把一整张网整体搬到另一张网上:对象搬到对象、箭头搬到箭头,并且保持接龙关系——原来 $A\to B\to C$ 接得起来,搬过去照样接得起来。

类比一张地图:它把真实地形(一个范畴)映射到纸面(另一个范畴),山川的具体形状丢了,但「相邻」「连通」这些关系被忠实保留。函子不是随便的映射,而是「尊重结构的翻译」——这个「尊重」正是它全部的分量所在。

范畴 C A B f 范畴 D FA FB Ff F
正式定义

函子 $F:\mathcal{C}\to\mathcal{D}$ 把每个对象 $A$ 映到 $F(A)$、每个态射 $f:A\to B$ 映到 $F(f):F(A)\to F(B)$,满足两条:保恒等 $F(\mathrm{id}_A)=\mathrm{id}_{F(A)}$;保复合 $F(g\circ f)=F(g)\circ F(f)$。第二条是灵魂——它说「先在原范畴组合、再搬」与「先搬、再在目标范畴组合」结果必然相同。正是这条等式,让「翻译」不会走样。

为什么美

函子是「同一个思想在不同世界之间的翻译器」。基本群 $\pi_1$ 就是从拓扑空间范畴群范畴的函子——它把「甜甜圈上的洞」翻译成「群里的元素」,于是难缠的几何问题变成可计算的代数问题。整门代数拓扑就靠这台翻译机运转。函子保结构的性质保证翻译忠实:几何里的连续形变,翻译到代数后仍是合法的等式。

应用

编程里 ListOption/MaybeFuture 都是函子——map 就是 $F(f)$,它把「作用在值上的函数」提升成「作用在容器上的函数」。这就是你能写 [1,2,3].map(f) 的原因。而保复合定律 map(g∘f)=map(g)∘map(f) 不只是漂亮:编译器据此把两次遍历融合成一次(fusion 优化),程序员也能放心重构而不改变语义。

一句话精华:函子 = 保持结构的翻译;它让「几何→代数」「值→容器」这样的跨界,成为一台可靠、可复用的机器。
思考题:把一个函数 map 进列表时,为什么「先合成两个函数再 map」与「map 两次」结果必然一致?若某个 map 违反了这条定律,它还配叫函子吗?会带来什么灾难?

自然变换

Natural Transformation · 把「自然」变成定理
Category Theory · 皇冠
直觉版

函子是两张网之间的「搬运方案」。如果你手上有两套方案 $F$ 和 $G$,自然变换就是从方案 $F$ 平滑过渡到方案 $G$ 的一套统一规则——而且这套过渡对每个对象都用「同一种方式」,绝不因对象不同而临时特殊处理。

「自然」二字的精确含义正是:这个变换不依赖任何人为选择,对所有对象、所有箭头一致成立。一段历史八卦:Eilenberg 与 Mac Lane 在 1945 年发明整个范畴论,最初的唯一动机就是给「自然」这个含糊的词一个精确定义——范畴和函子,其实是为了定义「自然变换」才被引入的配角。

F(A) F(B) G(A) G(B) F(f) G(f) η_A η_B 方块交换
正式定义

给两个函子 $F,G:\mathcal{C}\to\mathcal{D}$,自然变换 $\eta:F\Rightarrow G$ 为每个对象 $A$ 指定一支态射 $\eta_A:F(A)\to G(A)$(称「分量」),使得对每支 $f:A\to B$,下面这个自然性方块都交换(两条路径相等):

$$G(f)\circ\eta_A \;=\; \eta_B\circ F(f)$$

读作:先用 $\eta$ 变换、再搬(走下-右),与先搬、再用 $\eta$ 变换(走右-下),殊途同归。这条「无论从哪个对象出发都成立」的一致性,就是「自然」的数学本体。

为什么美

数学家几百年来一直在用「自然的同构」这个说法却说不清它。经典例子:有限维向量空间 $V$ 与它的双重对偶 $V^{**}$「自然地」同构,而与对偶 $V^*$ 只是「同构但不自然」——后者必须人为选定一组基才能建立。自然变换第一次把这种直觉钉成精确陈述:把一个哲学级别的形容词,变成了可证明或证伪的定理。这是范畴论最优雅的胜利之一。

应用

编程里,List → Option 的取首元素 headOption、列表 reverse,都是自然变换:它们对任何元素类型都用同一套逻辑,从不窥看里面装的是 Int 还是 String。这种「对类型参数一致」的性质,在 Haskell 里叫参数化多态(parametricity),正是 Philip Wadler「Theorems for free!」的核心——光看类型签名,无需看实现,就能免费推出函数必然满足的定律。

一句话精华:自然变换 = 函子之间「不搞特殊化」的一致过渡;它把「自然」这个含糊的赞美,钉成了精确定理。
思考题:为什么 $V\cong V^*$ 需要选基而「不自然」,$V\cong V^{**}$ 却「天然成立」?「需要人为选择」这件事,在范畴论里是如何被精确地识别并否定的?

证明、程序、态射:同一件事

Curry–Howard–Lambek & Monads · 抽象的顶点最实用
Type Theory · CS
直觉版

三样看似毫不相干的东西——逻辑里的证明、程序里的类型、范畴里的态射——竟是同一件事的三种方言。这叫 Curry–Howard–Lambek 对应:「类型 $A\to B$ 的一个程序」=「命题『$A$ 蕴含 $B$』的一个证明」=「范畴里从 $A$ 到 $B$ 的一支态射」。写对一个有类型的程序,就等于构造性地证明了一条定理。

Monad,是范畴论嫁给编程后最出名的孩子。纯函数容不下副作用(异常、状态、IO、异步),可真实程序离不开它们。Monad 用一个统一的结构把副作用装进盒子,让本会破坏纯粹性的东西重新变得可组合。

逻辑类型 / 程序范畴
命题 $A$类型 $A$对象 $A$
证明 $A\Rightarrow B$函数 $A\to B$态射 $A\to B$
合取 $A\wedge B$元组 $(A,B)$积 $A\times B$
析取 $A\vee B$联合类型 $A|B$余积 $A+B$
正式定义

一个 Monad 是一个自函子 $M:\mathcal{C}\to\mathcal{C}$,配两支自然变换:$\eta:\mathrm{Id}\Rightarrow M$(把纯值装进盒子,即 return)与 $\mu:M\circ M\Rightarrow M$(把双层盒子压平,即 join),且满足结合律与单位律。这就是那句著名「玩笑」的来历——「Monad 不过是自函子范畴里的一个幺半群」——听着像绕口令,其实字字精确:把幺半群定义里的「集合」换成「自函子」、「乘法」换成「函子复合」即可。

为什么美

Curry–Howard 揭示逻辑与计算是同一枚硬币——这是 20 世纪最深的思想统一之一。它让「证明即程序」成真,催生了 Coq、Lean、Agda 这类证明助手:机器能逐行检查数学证明的正确性,Kevin Buzzard 正用 Lean 把整个本科数学形式化。而 Monad 展示了反直觉的一面:一个纯抽象的范畴结构,居然精确解决了「如何在纯函数语言里做 IO」这个最接地气的工程难题。抽象的顶点,恰恰最实用。

应用

Haskell 的 IOMaybeState 全是 Monad;do 记号就是 Monad 组合的语法糖,async/await 本质也是这套结构。Curry–Howard 让「类型检查通过」等价于「证明正确」,已被用于产出带数学证明的软件:经形式验证的编译器 CompCert、操作系统内核 seL4,以及四色定理的机器验证证明,都建立在这条对应之上。

一句话精华:证明、程序、态射本是同一件事;Monad 更证明了最抽象的范畴结构,能解决最具体的工程问题。
思考题:若「写一个类型正确的程序」等价于「证明一条定理」,那么类型系统越强的语言,是否就越接近一个数学证明助手?这条路的尽头,人类数学家还剩下什么?
— 深入思考 —
「万有性质」为什么能取代具体构造?
范畴论定义「积」「余积」「极限」时,从不说它们由什么造成,只说它们满足什么关系——例如两个对象的积 $A\times B$,是「任何同时映向 $A$ 和 $B$ 的对象,都唯一地经它中转」的那个对象。这叫万有性质。它的威力在于:满足同一万有性质的对象必然唯一(在同构意义下),于是「怎么造」无关紧要,「起什么作用」才是本质。集合的笛卡尔积、群的直积、拓扑的乘积空间——同一个万有性质,一次定义处处适用。这正是范畴论「关系先于对象」哲学的最锋利体现。
伴随函子(adjunction)为什么被称为范畴论的心脏?
Mac Lane 有句名言:「Adjoint functors arise everywhere.」两个方向相反的函子 $F\dashv G$ 成伴随,是指 $\mathcal{D}(F A, B)\cong \mathcal{C}(A, G B)$ 自然地成立——一边的箭头总能一一对应到另一边。自由群构造 ⊣ 遗忘函子、张量积 ⊣ Hom、存在量词 ⊣ 替换……数学中大量「最优」「最自由」的构造,本质都是某个伴随。伴随捕捉的是「以最省力的方式跨越两个世界」的普遍模式,比函子更深一层,被认为是范畴论真正的核心。
Yoneda 引理到底在说什么?
Yoneda 引理是范畴论最基础也最深的定理,一句话概括:一个对象,被它「射向所有其他对象的箭头模式」唯一决定。你不必打开对象,只要知道「所有人怎么看它」(即所有 $\mathrm{Hom}(A,-)$),就完全掌握了它。这把概念 1 的直觉——「结构藏在关系里」——升级成了严格定理:对象与它的「关系画像」信息等价。它是现代代数几何、以及编程中「面向接口而非实现」思想的数学源头。
范畴论被讥为「general abstract nonsense」,它真有内容吗?
这绰号半是调侃半是敬意。批评者说它太抽象、只把已知结果换个说法;辩护者指出:正是这种抽象让 Grothendieck 重写了代数几何、让 Eilenberg–Steenrod 用几条公理统一了同调论。真正的答案或许是:范畴论本身少有「深定理」,价值在于提供正确的语言——一旦用对语言,原本晦涩的类比会变成一行显然的等式。它不常是结论,却常是让结论变得不可避免的框架。
范畴论能取代集合论,成为数学的基础吗?
这是一个真实的现代争论。传统上 ZFC 集合论是数学的地基——万物皆集合。但 Lawvere 与后来的 topos 理论提出:可以用「范畴」而非「集合」作基础,其中「元素」是派生概念、「关系」才是原初。topos 是一种「行为像集合范畴」的范畴,却能容纳直觉主义逻辑、内蕴不同的连续统。它把「结构」放在最底层,与范畴论「关系先于对象」的气质一脉相承——尽管它作为通用基础是否比 ZFC 更优,至今没有定论。