承接上一篇
這裡講解一個簡單的範例
第一步
我們先定義幾個基本且常見的東西
自然數(Nature Number)是一個type
一個自然數如果不是Zero就是某個自然數+1
data Nat : Set where
zero : Nat
suc : Nat -> Nat
對某一個type A, List A n是A上面的一個長度為n的List結構
一個List如果不是空的(Nil)就是某一個元素接上另一個List
data List {A : Set} : Nat -> Set where
nil : List A zero
cons : {m : Nat} -> (a : A) -> List A m -> List A (suc m)
關於我們的資料結構就那兩個而已,非常簡單
然後下面我們來定義幾個常用的function
_+_ : Nat -> Nat -> Nat
zero + n = n
(suc m) + n = suc (m + n)
_++_ : {A : Set} -> {m n : Nat} ->
List A m -> List A n -> List A (m+n)
nil ++ xs = xs
(cons x xs) ++ ys = Cons x (xs ++ ys)
前者是一般Nat在用的加法
後者是List在用的加法
"++"一般我們稱為 concat 或是 append
比較值得一提的是List A (m+n)這裡
我們知道m,n都是Nat, 而m+n也是一個Nat
問題在於,independent typed language中
我們是不能在type上做這樣operating的
例如說我們絕對不會看到
(double + String) var = ?? ;
這樣的東西出現在我們的java或是C++程式裡面
可是在agda中我們可以直接這樣做
這也就是上一篇中說得"value與type之間的曖昧不明"
再接下去下面的定義之前
我們先來看看目前為止我們可以做什麼?
more over, 有什麼好處?
(方便起見,這裡先用比較general的語法來表示)
假設我們現在有兩個List:
a = [1,2,3]
b = [4,5]
我們知道a, b兩者的type:
a : List Nat 3 (長度3的整數list)
b : List Nat 2 (長度3的整數list)
所以,我們可以想像出:
a ++ b : List Nat 5
a ++ b = [1,2,3,4,5]
這是非常理所當然的
我們腦海裡確實是這樣的結果
但是我們怎麼知道真正跑起來的時候 ++ 會是正確的?
或著說,我們希望能盡早確定這個function一定正確
那麼,最早,我們多早能確定呢?
如果我們可以抽象且廣泛的描述這個function
(也就是定義這個function的同時)
而且知道它一定會正確的執行
那麼對於每一個實際執行時的case
它都絕對會是正確的
否則這段有問題的code根本不會通過type checking
更別提還要執行了
稍微回憶一下++的定義
我們根據++的type知道對於長度為m, n的list a, b
它都會正確的產生出一個長度是(m+n)的list
所以我們知道它在我們重視長度問題時一定是正確的
他不可能會在跑 [1,2,3] ++ [4,5,6] 時跑出一個長度不是6的list
因為List Nat 5和 List Nat 6根本是不同的type
(to be continued)