2.9 由集合論看歸納法
歸納證明為何成立?本節試圖以集合論的角度理解歸納法,試圖建立幾個觀念:當我們說某型別是「歸納定義」的,常常代表它是具有某個結構的最小集合。而歸納證明可以理解為證明某型別是所有滿足某性質的事物的子集。本節於初次閱讀時可跳過。
序理論回顧 為了本章的完整性,我們在這兒回顧一些重要定義。 對學過序理論或抽象代數的讀者來說,以下概念應不陌生。 如果您還不熟悉這些定義,由於它們在程式語言語意中常常使用,值得花些時間弄懂。
定義 2.6 前序、偏序
給定集合$S$, 令 $(\leq)$ 為 $S$ 上的一個二元關係。如果 $(\leq)$ 滿足:
自反律:對所有 $x \in S$,
x <= x.遞移律:對所有 $x,y,z \in S$,
x <= y ⋀ y <= z ==> x <= z,
則 $(\leq)$ 被稱為$S$ 上的一個前序(preorder). 如果 $(\leq)$ 除上述兩性質外還滿足:
反對稱律:對所有 $x,y \in S$,
x <= y ⋀ y <= x ==> x = y.
則 $(\leq)$ 被稱為$S$ 上的一個偏序(partial order). 如果 $S$ 上有偏序 $(\leq)$, 我們常把它們放在一起,稱 $(S,(\leq))$ 為一個偏序集合(partially ordered set, 或 poset).
定義 2.7 最小上界、最大下界
給定偏序集合 $(S,(\leq))$,考慮其子集 $T \subseteq S$:
如果 $x \in S$ 滿足 $(\forall y \in T: y \leq x)$, 則 $x$ 是 $T$ 的一個上界(upper bound).
如果 $T$ 的所有上界中存在「最小」的,該值稱作 $T$ 的最小上界(supremum, 或 least upper bound), 記為 $\mathit{sup}~T$. 依據定義,$\mathit{sup}~T$ 滿足 $(\forall y \in T: y \leq x) \Rightarrow \mathit{sup}~T \leq x$.
如果 $x \in S$ 滿足 $(\forall y \in T: y \geq x)$, 則 $x$ 是 $T$ 的一個下界(lower bound).
如果 $T$ 的所有下界存在「最大」的,該值稱作 $T$ 的最大下界(infimum, 或greatest lower bound), 記為 $\mathit{inf}~T$. 依據定義,$\mathit{inf}~T$ 滿足 $(\forall y \in T: y \geq x) \Rightarrow \mathit{inf}~T \geq x$.
定義 2.8 格、完全格
考慮偏序集合 $(S,(\leq))$:
如果對任何 $x, y \in S$,
sup {x,y}和inf {x,y}均存在且都在 $S$ 之中,則 $(S,(\leq))$ 是一個格 (lattice)。如果對任何 $T \subseteq S$,$\mathit{sup}~T$ 和 $\mathit{inf}~T$ 均存在且都在 $S$ 之中,則 $(S,(\leq))$ 是一個完全格 (complete lattice)。
在本節之中我們只會考慮一種格。令 $D$ 代表所有範式(如 Zero, Suc Zero, True, 1 : 2 : [], (\x -> x)...)的集合,我們考慮的格是 ${\cal P}D$,即 $D$ 的所有子集形成的集合。其上的偏序就是子集關係 $(\subseteq)$.
定點 再回顧一些與定點相關的理論。
定義 2.9 定點
給定完全格 (A, (<=)) 和函數 f :: A -> A,
如果
f x <= x, 我們說x是f的一個前定點 (prefixed point).如果
f x = x, 我們說x是f的一個定點 (fixed point).如果
f x >= x, 我們說x是f的一個後定點 (postfixed point).
定義 2.10 最小前定點、最大後定點
給定完全格 (A, (<=)) 和函數 f :: A -> A,
如果
f的前定點之中存在最小值,我們將它記為mu f. 根據此定義,mu f滿足f x <= x ==> mu f <= x.如果
f的後定點之中存在最大值,我們將它記為nu f. 根據此定義,nu f滿足x <= f x ==> x <= nu f.
定理 2.11
給定完全格 (A, (<=)) 和函數 f :: A -> A,
f的最小前定點mu f也是最小的定點,f的最小前定點nu f也是最大的定點。
歸納定義 回顧自然數的定義:
data Nat = Zero | Suc Nat
第2.1 節對這行定義的解釋是:
Zero的型別是Nat;如果
n的型別是Nat,Suc n的型別也是Nat;此外,沒有其他型別是
Nat的東西。
如果我們把一個型別視作一個集合,上述條件定出了怎麼樣的集合呢?
請注意:「把型別視為集合」僅在簡單的語意之中成立。本書後來將會討論更複雜的語意,屆時型別並不只是集合。
用 Nat 表示我們定出的這個新型別。上述第 1.點告訴我們 Zero 是 Nat 的成員,也就是 {Zero} ⊆ Nat. 第 2.點則表示,從 Nat 這個集合中取出任一個元素 n, 加上 Suc, 得到的結果仍會在 Nat 之中。也就是說 {Suc n | n ∈ Nat} ⊆ Nat. 集合基本定理告訴我們 X ⊆ Z ⋀ Y ⊆ Z 和
X ∪ Y ⊆ Z 是等價的,所以:
X ⊆ Z ⋀ Y ⊆ Z <=> X ∪ Y ⊆ Z 被稱為「(∪) 的泛性質」。
{Zero} ∪ { Suc n | n ∈ Nat } & ~\subseteq~ Nat (2.8 )
意思是說,如果我們定義一個集合到集合的函數 NatF:
NatF X = {Zero} ∪ { Suc n | n ∈ X }
那麼 (2.8 ) 可以改寫為
NatF Nat &~\subseteq~ Nat \mbox{~~,}也就是說,Nat 是 NatF 的一個前定點!
至於 3.呢?它告訴我們 Nat 僅含恰巧能滿足 1.和 2.的元素,沒有多餘。
意即,Nat 是滿足 1.和 2.的集合之中最小的。
若有另一個集合 Z 也滿足 1.和 2., 我們必定有 Nat ⊆ Z.
也就是說 Nat 是 NatF 的最小前定點:Nat = mu NatF!
給定述語P, 我們把所有「滿足 P 的值形成的集合」也記為 P.
對任何 A, 函數 P :: A -> Bool 和「滿足 P 的 A 形成的集合」是同構的。我們可把它們等同視之。
數學歸納法的目的是證明所有自然數都滿足 P。
但,「所有自然數都滿足 P」其實就是 Nat ⊆ P.
如何證明 Nat ⊆ P? 如前所述,Nat 是 NatF 的最小前定點。
如果 P 恰巧也是 NatF 的一個前定點,Nat ⊆ P 一定得成立。
寫成推論如下:
Nat ⊆ P
<== {- Nat 是 NatF 的最小前定點,定義2.10 -}
NatF P ⊆ P
<=> {- NatF 的定義 -}
{Zero} ∪ {Suc n | n ∈ P} ⊆ P
<=> {- (∪) 的泛性質:X ∪ Y ⊆ Z <=> X ⊆ Z ⋀ Y ⊆ Z -}
{Zero} ⊆ P ⋀ {Suc n | n ∈ P} ⊆ P
也就是說,如果證出{Zero} ⊆ P 和 {Suc n | n ∈ P} ⊆ P,我們就有 Nat ⊆ P。其中,
{Zero} ⊆ P翻成口語便是「P對Zero成立」,{Suc n | n ∈ P} ⊆ P則是「若P對n成立,P對Suc n亦成立」。
正是數學歸納法的兩個前提!
原來,數學歸納法之所以成立,是因為自然數被定義為某函數的最小前定點。 事實上,當我們說某型別是「歸納定義」的,意思便是它是某個函數的最小前定點。
以串列為例。為單純起見,先考慮元素皆為 Nat 的串列。
如下的定義
data ListNat = [] | Nat : ListNat
可理解為 ListNat = mu ListNatF,而 ListNatF 定義為:
ListNatF X = { [] } ∪ { n : xs | xs ∈ X, n ∈ Nat }
至於如下定義的、有型別參數的串列,
data List a = [] | a : List a
則可理解為 List a = mu(ListF a) --- List a 是 ListF a 的最小前定點,其中 ListF 定義如下:
ListF A X = { [] } ∪ { x : xs | xs ∈ X, x ∈ A }
給定某型別 A, 當我們要證明某性質 P 對所有 List A 都成立,實質上是想要證明 List A ⊆ P (同樣地,此處 P 代表所有使述語 P 成立的值之集合)。我們推論如下:
List A ⊆ P
<== {- List a = mu(ListF a) -}
ListF A P ⊆ P
<=> {- ListF 之定義 -}
{ [] } ∪ { x : xs | xs ∈ P, x ∈ A } ⊆ P
<=> {- (∪) 的泛性質 -}
{[]} ⊆ P ⋀ { x : xs | xs ∈ P, x ∈ A } ⊆ P
其中 {[]} ⊆ P 翻成口語即是「P [] 成立」;
{ x : xs | xs ∈ P, x ∈ A } ⊆ P 則是
「若 P xs 成立,對任何 x::A, P (x:xs) 成立」。
我們之所以能做自然數與串列的歸納證明,因為它們都是歸納定義出的型別 --- 它們都被定義成某函數的最小前定點。若非如此,歸納證明就不適用了。 那麼,有不是歸納定義出的型別嗎?
讀者可能注意到,本節起初同時談到最小前定點與最大後定點,但後來只討論了前者。 事實上,我們也可以把一個資料型別定義為某函數的最大後定點。 這時我們說該資料型別是個餘歸納(coinductive)定義,如此訂出的型別稱為餘資料(codata)。 歸納定義出的資料結構是有限的,而餘歸納定義的型別可能包括無限長的資料結構。 寫餘資料相關的證明,另有一套稱作餘歸納(coinduction)的方法, 而餘歸納也影響到我們如何寫與餘資料相關的程式。 餘歸納和歸納的相關理論剛好是漂亮的對偶。我們將在 \todo{where} 介紹餘歸納。
練習 2.36
回顧第1.10 節中介紹的兩種樹狀結構:
data ITree a = Null | Node a (ITree a) (ITree a)
data ETree a = Tip a | Bin (ETree a) (ETree a)
說說看它們分別是什麼函數的最小前定點,並找出它們的歸納原則。