跳轉到

6.1 命題即型別證明即程式#

本章導讀#

本章是全書的理論高峰 , 把程式與證明正式連成一體 。 核心口號只有一句 , 命題即型別 , 證明即程式 。 學完本章 , 你能讀懂項式證明 , 並在項式與 tactic 兩種風格間切換 。 我們以合取交換律為主線例子 , 給出兩種證明的逐行對照 。 下一節 6.2 會處理這個對應的邊界 , 即宇宙與公理的取捨 。 建議先複習 02.2 節的合取規則 , 對照閱讀效果最佳 。

淺顯說明#

把命題看成型別 , 把證明看成住在裡面的程式 , 化簡證明就像執行程式 。 例如命題 \(p\land q\) 對應積型別 , 證據就是一對有序對 。 命題 \(p\to q\) 對應函數型別 , 證據就是把證據變成證據的函數 。 命題 \(p\lor q\) 對應和型別 , 證據要註明來自左邊或右邊 。 證明檢查等於型別檢查 , 寫錯證明就像傳錯參數型別 。 tactic 只是幫你慢慢拼出這支程式的助手 , 最終產物仍是一項程式 。 這就是 Gentzen 自然演繹在 Lean 中的復活 , 引入規則即構造 , 消去規則即使用 。 項式證明一次寫完答案 , tactic 證明一步步請電腦幫忙填空 。 兩者沒有高下之分 , 只是同一個程式的不同寫法 。

正規理論#

Curry-Howard 對應可用三對照表一覽 , 邏輯概念逐項翻譯為型別概念 。

邏輯側 型別側 直觀讀法
命題 \(p\) 型別 \(P\) 規格即型別
證明 \(h\) 程式 \(e\) 證據即程式碼
化簡 \(h\) 求值 \(e\) 正規化即執行

三個核心邏輯連結詞的翻譯如下 , 每一條都是獨立公式 。

\[ Proof(p\land q)\simeq Proof(p)\times Proof(q) \]
\[ Proof(p\to q)\simeq(Proof(p)\to Proof(q)) \]
\[ Proof(p\lor q)\simeq(Proof(p)+Proof(q)) \]

其中符號 \(Proof\) 表示某命題的證據集合 , 符號 \(\simeq\) 表示一一對應 。 Gentzen 的自然演繹規則恰好落在構造與消去的位置 , 見下表 。

Gentzen 規則 項式寫法 tactic 寫法
合取引入 構造子 And.intro constructor
合取消去 投影 h.1 與 h.2 cases
蘊涵引入 匿名函數 fun intro
蘊涵消去 函數套用 apply

引入規則負責製造證據 , 消去規則負責使用證據 , 與構造子及 \(match\) 完全平行 。 tactic 證明的每一步 , 其實都是在反向拼裝右欄對應的左欄項 。 理解這一點之後 , tactic 不再是魔法咒語 , 而是項式程式的互動組裝器 。

簡易範例#

下面用合取交換律示範同一個定理的兩種證明 , 請逐行對照閱讀 。 項式版本只有一行核心 , tactic 版本則把構造過程攤開 。

def and_comm_fun {p q : Prop} : p ∧ q → q ∧ p :=
  fun h => And.intro h.2 h.1

theorem and_comm_tac {p q : Prop} (h : p ∧ q) : q ∧ p := by
  cases h with
  | intro hp hq =>
    constructor
    · exact hq
    · exact hp

項式版的 fun h => 對應 tactic 版的接住假設 \(h\) 的動作 。 項式版的 And.intro 對應 tactic 版的 constructor 步驟 。 項式版的 \(h.2\) 與 \(h.1\) 對應 tactic 版拆開後的 \(hq\) 與 \(hp\) 次序 。 tactic 版的兩個 exact 只是把交換後的證據逐一放回 goals 。 當你對 tactic 證明呼叫顯示項命令時 , 會看到它生成的正是類似項式版的程式 。 初學建議先用 tactic 摸索 , 熟練後再試著直接寫出項式一行解 。

歷史典故#

這個對應的發現者是 Howard 公式即型別 。 該卷宗記載他如何把 Gentzen 的自然演繹逐條翻譯成型別項 。 而型別一側的源頭 , 則是 Church 簡單型別理論 。 沒有簡單型別演算的函數觀念 , 公式即型別便無從附著 。 這個對應的集大成者是 CoC 與 CIC 。 構造演算把命題宇宙與資料宇宙統一在同一個依賴型別框架之下 。 其後的 Coq 誕生 讓程式設計師與數學家共用同一種語言 。 讀本章時 , 不妨把 Gentzen 想成提供文法的人 , Howard 想成發現雙語詞典的人 。

習題#

  1. 用項式風格證明蘊涵的傳遞性 , 即由 \(f\) 與 \(g\) 構造合成函數 , 再用 tactic 風格證明同一命題並對照兩者的對應行 。
  2. 把合取消去的兩個投影 \(h.1\) 與 \(h.2\) 改寫成 \(match\) 表達式 , 說明投影只是模式匹配的語法糖 。
  3. 解釋為何 tactic 證明最終仍產生一項程式 , 並說明這句話與 Gentzen 消去規則的關係 。