Agda

Agda 是一個依賴型別的純函數語言程式設計語言。目前的版本，Agda 2，最初由瑞典查爾摩斯工學院的 Ulf Norell 作為博士論文課題設計並實現。先前的版本 Agda 1 由 Catarina Coquand 在 1999 年開發，而現今的版本則是對其的徹底重寫，因此可視作一個全新的語言，但保留了 Agda 的命名和傳統。

Agda 的型別系統體現了柯里 - 霍華德同構（Curry-Howard correspondence），因此亦可作為一個構建構造性證明的。它的型別理論基於 Zhaohui Luo 提出的 UTT（unified theory of dependent types），與 Per Martin-Löf 的直覺型別論相似。

Agda 與另一個基於依賴型別的證明輔助工具 Coq 設計上存在著顯著的不同之處：它本身並不提供單獨的證明策略語言（tactics），所有的證明均以函數語言程式設計的方式書寫；Agda 擁有許多常規的函式式程式語言要素，諸如：資料型別（data types）、模式匹配（pattern matching）、記錄型別（records）、let 表示式和模組（modules）等，而其語法設計則高度仿照 Haskell 語言。

使用者可透過 Emacs 或 Atom 編輯器的介面與 Agda 系統進行互動。Agda 系統亦可藉由命令列單獨呼叫。

透過型別檢查的 Agda 程式可以被編譯到 Haskell，並由 GHC 編譯器最終編譯為可執行的本地機器碼；亦有編譯到 JavaScript 的後端實現。

Agda 的名字來自於一首由音樂家 Cornelis Vreeswijk 創作的瑞典語歌曲 “Hönan Agda”，歌詞講述了一隻名叫 Agda 的母雞的故事。這實際上影射了 Coq（Coq 在法語中意為公雞）。

簡介

1.1 一個簡單的 “Hello world” 程式

將下述程式保存於檔案 hello-world.agda 中：

module hello-world where

open import IO

main = run (putStrLn "Hello, World!")

在 Emacs 中可使用 C-c C-x C-c 來編譯此程式；或在命令列中執行 agda --compile hello-world.agda 進行編譯。

幾點解釋：

Agda 程式以模組（module）的形式組織而成。每一個檔案中的第一個模組稱之為最高級別（top-level）模組，其名稱必須和檔名相符。模組的內容可以包括資料型別的定義、函式的定義等。
外部模組可以透過 import 子句匯入。例如在上述程式中，open import IO 匯入 Agda 標準庫中的 IO（標準輸入輸出）模組，並將其在當前作用域中開啟。
一個匯出了函式名及型別簽名 main : IO a 的模組即可以被編譯成可執行檔案。例如，上述程式中的 main 函式作用是將字串 “Hello, World!” 寫到標準輸出，之後退出程式。

1.2 歸納型別（inductive types）

在 Agda 中定義資料型別的方式與其它（非依賴型別）程式語言中的代數資料型別相似。

例如，在 Agda 中歸納地定義皮亞諾數：

data ℕ : Set where

zero : ℕ

succ : ℕ → ℕ

這表明存在兩種形式可以用來構造一個自然數：首先，zero 是一個自然數；若已知 n 是一個自然數，則 succ n 也必定是一個自然數。

又如，Agda 中對小於或等於關係的定義：

data ≤ : ℕ → ℕ → Set where

z≤n : {n : ℕ} → zero ≤ n

s≤s : {n m : ℕ} → n ≤ m → succ n ≤ succ m

第一處構造（z≤n）指出：zero 必定小於或等於任何自然數；第二處構造（s≤s）指出：當 n z≤n {succ zero}，依照定義，它是對零小於一的證明；再考慮 s≤s {zero} {succ zero} (z≤n {succ zero})，則是對一小於二的證明。

1.3 依賴型別模式匹配（dependently typed pattern matching）

在型別論中，歸納和遞迴原則通常被用來證明涉及到歸納型別的定理。Agda 則使用依賴型別模式匹配來達到此目的。例如，自然數的加法可被定義為：

add zero n = n

add (succ m) n = succ (add m n)

比起運用歸納 / 遞迴原則，直接定義遞迴函式更加簡單直觀。依賴型別模式匹配是 Agda 內建的語言特性之一；其核心型別論並沒有包含歸納 / 遞迴原則。

1.4 記錄型別（records）

除了歸納型別之外，Agda 還支援記錄型別。記錄的作用是將若干型別的值包裝在一起，並使用不同名稱標識不同的域；它可看作是對依賴乘積型別（dependent product types）的推廣。

例如，在 Agda 中定義一個值對（pair）：

record Pair (A B : Set) : Set where

field

fst : A

snd : B

以上程式碼定義了一個新的資料型別 Pair : Set → Set → Set，以及兩個投影函式：

Pair.fst : {A B : Set} → Pair A B → A

Pair.snd : {A B : Set} → Pair A B → B

記錄型別的值可以使用記錄表示式來建立，如：

p12 = record {fst = 1; snd = 2}

若在定義記錄型別時使用 constructor 關鍵字規定了構造器，則亦可直接使用相應的構造器來建立記錄，如：

record Pair (A B : Set) : Set where

constructor ,

field

fst : A

snd : B

p34 : Pair Nat Nat

p34 = 3 , 4

1.5 元變數（metavariables）

Agda 和其他類似的互動式證明系統（如 Coq）相比，一個顯著的特性是在證明構造中對元變數的大量利用。

例如，在 Agda 中可以寫出如下函式：

add : ℕ → ℕ → ℕ

add x y = ?

“?” 即是一個元變數。在 Emacs mode 中互動時，系統會提示使用者所期望的型別，允許使用者進一步新增具體程式碼到其中。該特性為漸進式程式構造提供了支援，從而達到與 Coq 的證明策略（tactics）類似的意圖。

1.6 證明自動化和反射（reflection）

1.7 宇宙（universe）

1.8 高階歸納型別（higher inductive types）

1.9 終止檢查（termination checking）

作為一個定理證明系統，Agda 語言中的定義必須是完整（total）的。所有的程式必須終止，所有的模式必須得到匹配。若無法保證定義的完整性，其型別論背後所對應的邏輯將失去一致性，導致假命題可以被證明。

目前 Agda 使用 Foetus 終止檢查器。

1.10 Unicode

Agda 語言大量吸收了 Unicode 字元集中的數學符號，這使得其證明更具可讀性。Agda 的 Emacs mode 中提供了輸入這些符號的快捷鍵；這仿照 TeX 中書寫數學符號的形式。例如，輸入 Σ 可以使用 \Sigma。

1.11 標準庫

Agda 的標準庫包含了一些常見資料結構的定義和相關的定理證明，例如自然數、列表（lists）與向量（vectors）。

1.12 編譯器

Agda 目前具備兩個官方的編譯器後端：編譯到 Haskell 的 MAlonzo 後端；和另一個編譯到 JavaScript 的後端。