04.3 羅素悖論與型別論的誕生:避免數學體系崩潰的防火牆#
引言:數學的 Chernobyl 時刻#
1901 年,羅素(Bertrand Russell)寄給弗雷格(Gottlob Frege)一封信,信末附了一個問題。弗雷格晚年回憶,這封信讓他的畢生工作「地基動搖」。那個問題就是羅素悖論——它不只是一個邏輯謎題,而是暴露了當時整個數學基礎(樸素集合論)的內在矛盾。
本節的主線是:型別論不是程式設計師的發明,而是數學家為了拯救數學而建造的防火牆。而一百年後,這道防火牆以「型別系統」的身份,回到了每個程式語言的編譯器裡。
1. 前因:弗雷格的野心#
弗雷格在《算術基礎》(1884)與《算術基本法則》(1893)中提出宏偉計畫:把全部算術還原為純邏輯(邏輯主義 logicism)。他的工具是:
- 概念(concept):從對象到真值的函數,如「 \(x\) 是素數」;
- 外延(extension):一個概念所適用的所有對象的集合,記作 \(\hat{x}\, F(x)\) ;
- 基本法則 V(Basic Law V):兩個概念的外延相等,若且唯若它們對所有對象的取值相同。
這條法則讓「任何條件都可以定義一個集合」變成邏輯真理。看似無害,實則埋著炸彈。
2. 定義:羅素悖論#
定義 2.1(羅素集合). 考慮所有「不包含自身」的集合:
定理 2.1(羅素悖論,1901). 在樸素集合論中, \(R\) 的存在導致矛盾。
證明. 問: \(R \in R\) ?
- 若 \(R \in R\) ,則依 \(R\) 的定義, \(R \notin R\) ;
- 若 \(R \notin R\) ,則 \(R\) 滿足成員條件,故 \(R \in R\) 。
兩種情況皆矛盾。 \(\blacksquare\)
用弗雷格的系統說:把 \(F(x)\) 取為「 \(x \notin x\) 」,Basic Law V 保證外延 \(\hat{x}\, F(x)\) 存在,於是矛盾是在公理層面推導出來的——弗雷格的系統是不一致的,任何命題都能證明。
2.1 悖論的結構:「自我指涉 + 否定」#
羅素悖論的骨架是對角線論證(diagonal argument),同一結構還出現在:
| 年代 | 悖論 | 結構 |
|---|---|---|
| 1874 | Cantor:實數不可數 | \(f(x) \ne\) 第 \(x\) 個的對角線值 |
| 1897 | Burali-Forti:所有序數的集合 | 序數集合的序數 \(\notin\) 自己 |
| 1901 | Russell: \(R = \{x \mid x \notin x\}\) | 自我否定 |
| 1931 | Gödel 不完備定理 | \(\ulcorner\) 本命題不可證 \(\urcorner\) |
| 1936 | Turing 停止問題 | 對角線程式 |
flowchart TD
A[自我指涉<br/>x 指向 x] --> B[否定<br/>x 不屬於 x]
B --> C[對角線矛盾]
C --> D1[羅素悖論 1901]
C --> D2[Godel 不完備 1931]
C --> D3[停止問題 1936]
D1 --> E[型別論]
D3 --> F[可計算性理論]3. 解法一:Zermelo 公理化集合論(限制「哪些集合存在」)#
Zermelo(1908)的策畧:保留「集合」這個概念,但不讓任意條件都生成集合。分離公理(Separation)只允許從既有集合中切出子集:
於是 \(R = \{x \mid x \notin x\}\) 只能在某個 \(a\) 之內定義, \(R \in R\) 的問題變成「 \(a\) 是否包含自身」——不導致全域矛盾,只導致「 \(a\) 不是所有集合的集合」。搭配正則公理( \(x \notin x\) 對一切集合恆真),矛盾被排除。
4. 解法二:型別論(限制「誰能屬於誰」)#
羅素本人的解法走的是另一條路:分層。
定義 4.1(簡單型別論). 對象分為層級:
- 層 0:個體(individuals,不談成員關係);
- 層 \(n+1\) :層 \(n\) 物件的集合(更精確地:層 \(n\) 上的性質)。
成員關係只允許「低層屬於高層」:
「 \(x \in x\) 」這個公式在語法層面就是非法的——不是被證明為假,而是根本不能寫出來。悖論不是被解決,而是被禁止。
4.1 防火牆的比較#
| ZFC 集合論 | 型別論 | |
|---|---|---|
| 策畧 | 限制集合的生成 | 限制成員關係的語法 |
| 悖論的命運 | 被公理排除 | 被語法禁止 |
| 全集 \(V\) | 不存在(是「真類」) | 每層有自己的全集 |
| 程式對應 | 較少 | 就是型別系統 |
5. 從邏輯型別論到程式型別:Church 的綜合#
1940 年,Church 把羅素的分層思想移植到 \(\lambda\) 演算上,得到簡單型別蘭布達演算(04.2 的主角)。連接點正是:
「函數不能應用到自己身上」⇔「集合不能包含自身」。型別系統就是集合論正則性的語法化。羅素悖論的防火牆,在編譯器裡以「型別錯誤」的形式日夜運轉。
5.1 範例:三種語言中的防火牆#
# Python 的「動態防火牆」:語法允許自我應用,執行期才爆炸
f = lambda x: x(x)
f(f) # RecursionError: maximum recursion depth exceeded
# Python 沒有靜態層級,所以羅素式的項能通過檢查——代價是執行期風險
-- Haskell 的「靜態防火牆」:自我應用無法通過型別檢查
-- f x = x x -- 編譯錯誤:Occurs check: cannot construct the infinite type:
-- -- t = t -> t0
-- 注意錯誤訊息的名字:Occurs check!
-- 這正是「x 出現在自身型別中」被檢出的機制——羅素悖論的計算版偵測器
-- Lean 4 的「邏輯防火牆」:試圖在型別層重現羅素集合
-- universe u
-- def R : Type := { x : Type // x ∉ x } -- 語法上要求 x 與其成員關係不同層
-- 在依賴型別論中,Type : Type 被禁止,代之以型別宇宙層級 Type 0 : Type 1 : Type 2 : ...
-- 這正是羅素分層的現代形式(Russell 宇宙),詳見 06.3
Haskell 的 occurs check 特別值得品味:Hindley–Milner 推導在統一(unify) \(\alpha\) 與 \(\alpha \to \beta\) 時,檢查 \(\alpha\) 是否「出現在」待統一的型別內部——這個檢查的名字與數學上的「無基礎(non-well-founded)」禁止,是同一件事。
5.2 用 Python 驗證對角線結構#
def diagonal_contraption(pairs: list[tuple[int, int]]) -> int:
"""Cantor 對角線:構造與列表中每一列都不同的數。
這是羅素悖論、Godel 編碼、停止問題共用的骨架。"""
return 1 + pairs[0][0] # 第 0 列的第 0 項不同
# 完整版:d[i] = (pairs[i][i] + 1) % 2,d 與每一列在對角線位置不同
def cantor_theorem_demo():
"""定理(Cantor):不存在從 N 到 P(N) 的滿射。
給定任何 f: N -> P(N),構造 D = { n | n notin f(n) }。
若 D = f(k),則 k in D <=> k notin f(k) = D,矛盾。
這個 D 就是羅素集合 R 的相對化版本——差別只在:
Cantor 在 P(N) 內部做對角線(安全),
Russell 對「所有集合的全集」做對角線(爆炸)。"""
f = {0: {1, 2}, 1: {0}, 2: {0, 1, 2}} # f(n) ⊆ N 的例子
D = {n for n, s in f.items() if n not in s}
print(D) # {0, 1}:D 不等於任何 f(n),滿射被破壞
6. 定理:型別論的一致性#
定理 6.1. 簡單型別蘭布達演算是一致的:空型別(記作 \(\bot\) 或 Void)沒有居民,即不存在型別良好的閉項 \(e : \bot\) 。
證明. 由強正規化定理(04.2 定理 3.3), \(e\) 化約到正規形式 \(v\) 。正規形式不能是 \(\lambda x.\, b\) (因為 \(\lambda x.\, b : \bot\) 要求 \(\bot = \tau_1 \to \tau_2\) ,型別語法上不可能)。也不能是變數(閉項無自由變數)、不能是應用(正規形式不含紅色項)。無任何情況成立,故 \(e\) 不存在。 \(\blacksquare\)
由 Curry–Howard:型別論一致 ⇔ 沒有「型別為假」的程式。防火牆的防火牆,就是 04.2 那條定理。
7. 後果:一場危機,三個遺產#
羅素悖論的餘波塑造了二十世紀數學與計算的三條主線:
- 公理化集合論(ZFC):成為多數數學家的工作基礎;
- 型別論:經 Curry–Howard 轉化為證明助理(Coq、Lean、Agda)的基礎,今日菲爾茲獎級成果(如液體張量猜想)已在 Lean 中形式化;
- 可計算性理論:對角線方法的純化(Gödel、Turing),奠定電腦科學。
對程式設計師而言,每次編譯器拒絕一個型別錯誤的程式,都是 1901 年那場危機的迴聲:自我指涉被分層擋在門外,數學與程式因此不會崩潰。
8. 章末小結#
- 羅素悖論( \(R = \{x \mid x \notin x\}\) )使樸素集合論與弗雷格系統不一致。
- 兩種防火牆:ZFC 限制集合生成;型別論限制成員關係的語法(分層)。
- Church 的 STLC = 羅素分層 + \(\lambda\) 演算;「 \(x\,x\) 非法」⇔「 \(x \in x\) 非法」。
- Haskell 的 occurs check 是悖論偵測器的現代名字。
- 強正規化 ⇒ 空型別無居民 ⇒ 邏輯一致。
- 對角線方法一魚三吃:Cantor、Gödel、Turing。
下一步#
我們已有了型別的安全保證與邏輯對應,但型別還很貧乏:只有基本型別與箭頭。接下來進入第五章,為型別世界補上積(tuple/struct)與和(enum/Either)——你將看到代數型別如何讓「資料結構」與「邏輯連接詞 \(\land\) 、 \(\lor\) 」再次嚴格對應,並引出「型別即代數式」的驚人視角。