[_] : ∀{l} {A : Set l} -> A -> List A [ x ] = x :: []
is_empty : ∀{l} {A : Set l} -> List A -> Bool is_empty [] = true is_empty _ = false
head : ∀{l} {A : Set l} -> (x : List A) -> (is_empty x ≡ false) -> A head [] () head (x :: xs) _ = x
_++_ : ∀{l} {A : Set l} -> List A -> List A -> List A [] ++ ys = ys (x :: xs) ++ ys = x :: (xs ++ ys)
map : ∀{l} {A B : Set l} -> (A -> B) -> List A -> List B map f [] = [] map f (x :: xs) = f x :: map f xs
filter : ∀{l} {A : Set l} -> (A -> Bool) -> List A -> List A filter p [] = [] filter p (x :: xs) with p x ... | true = x :: filter p xs ... | false = filter p xs
foldr : ∀{l} {A B : Set l} -> (A -> B -> B) -> B -> List A -> B foldr f z [] = z foldr f z (x :: xs) = f x (foldr f z xs)
需要注意的是上面的 filter 函数,我们使用了 with 关键字,这个关键字可以让我们在函数中使用 pattern matching,这样我们就可以根据不同的情况进行不同的处理,相当于分类讨论。
map-++ : ∀{l} {A B : Set l} -> (f : A -> B) -> (xs ys : List A) -> map f (xs ++ ys) ≡ (map f xs) ++ (map f ys) map-++ f [] ys = refl map-++ f (x :: xs) ys rewrite map-++ f xs ys = refl
证明这两个性质都是容易的,按照之前对这些函数的定义展开就行了,他们的思想也都是一样的,都是对 List 进行归纳。
List 的一些定理(续)
length 与 filter 的关系:
1 2 3 4 5 6 7 8 9
postulate ≤ℕ-trans : ∀ {x y z : ℕ} -> x ≤ℕ y ≡ true -> y ≤ℕ z ≡ true -> x ≤ℕ z ≡ true ≤ℕ-suc : ∀ (x : ℕ) -> x ≤ℕ suc x ≡ true
length-filter : ∀{l} {A : Set l} -> (p : A -> Bool) -> (xs : List A) -> length (filter p xs) ≤ℕ length xs ≡ true length-filter p [] = refl length-filter p (x :: xs) with p x ... | true = length-filter p xs ... | false = ≤ℕ-trans {length (filter p xs)} (length-filter p xs) (≤ℕ-suc (length xs))
filter-idem : ∀{l} {A : Set l} -> (p : A -> Bool) -> (xs : List A) -> filter p (filter p xs) ≡ filter p xs filter-idem p [] = refl filter-idem p (x :: xs) with keep (p x) ... | true , p' rewrite p' | p' filter-idem p xs = refl ... | false , p' rewrite p' = filter-idem p xs
这个定理的证明是需要分类讨论的,我们使用了 with 关键字进行分类讨论,而在分类讨论的时候,我们使用了 keep 函数,来在之后使用 p(x) 的值。
open import Relation.Binary.PropositionalEquality -- to use inspect
filter-idem : ∀{l} {A : Set l} -> (p : A -> Bool) -> (xs : List A) -> filter p (filter p xs) ≡ filter p xs filter-idem p [] = refl filter-idem p (x :: xs) with (p x) | inspect (p x) ... | true | [ p' ] rewrite p' | p' filter-idem p xs = refl ... | false | [ p' ] rewrite p' = filter-idem p xs
但是 inspect 的构造器 [_] 会和 List 的构造器 [_] 冲突,所以我们可能需要改一些名字。
小练习
定义一个 List 的函数 takewhile ,它接受一个 List 和一个 Bool 函数,然后返回这个 List 中满足这个 Bool 函数的最长前缀。
定义一个 List 的函数 repeat ,它接受一个任意类型的元素和一个 Nat,然后返回一个 List,这个 List 中的元素都是这个任意类型的元素,而这个 List 的长度就是这个 Nat。
证明一个性质:takewhile p (repeat n a) ≡ repeat n a,其中 p 是一个 Bool 函数,n 是一个 Nat,a 是一个任意类型的元素,当然使用的是你自己定义的 repeat 和 takewhile 函数。
open import natural open import Data.Bool import Relation.Binary.PropositionalEquality as Eq open Eq using (_≡_; refl; cong) open Eq.≡-Reasoning using (begin_; step-≡; step-≡˘; _≡⟨⟩_; _∎)
data List {l} (A : Set l) : Set l where [] : List A _::_ : (x : A) -> (xs : List A) -> List A
[_] : ∀{l} {A : Set l} -> A -> List A [ x ] = x :: []
is_empty : ∀{l} {A : Set l} -> List A -> Bool is_empty [] = true is_empty _ = false
head : ∀{l} {A : Set l} -> (x : List A) -> (is_empty x ≡ false) -> A head [] () head (x :: xs) _ = x
length : ∀{l} {A : Set l} -> List A -> ℕ length [] = zero length (x :: xs) = suc (length xs)
_++_ : ∀{l} {A : Set l} -> List A -> List A -> List A [] ++ ys = ys (x :: xs) ++ ys = x :: (xs ++ ys)
map : ∀{l} {A B : Set l} -> (A -> B) -> List A -> List B map f [] = [] map f (x :: xs) = f x :: map f xs
filter : ∀{l} {A : Set l} -> (A -> Bool) -> List A -> List A filter p [] = [] filter p (x :: xs) with p x ... | true = x :: filter p xs ... | false = filter p xs
foldr : ∀{l} {A B : Set l} -> (A -> B -> B) -> B -> List A -> B foldr f z [] = z foldr f z (x :: xs) = f x (foldr f z xs)
map-++ : ∀{l} {A B : Set l} -> (f : A -> B) -> (xs ys : List A) -> map f (xs ++ ys) ≡ (map f xs) ++ (map f ys) map-++ f [] ys = refl map-++ f (x :: xs) ys rewrite map-++ f xs ys = refl
postulate ≤ℕ-trans : ∀ {x y z : ℕ} -> x ≤ℕ y ≡ true -> y ≤ℕ z ≡ true -> x ≤ℕ z ≡ true ≤ℕ-suc : ∀ (x : ℕ) -> x ≤ℕ suc x ≡ true
length-filter : ∀{l} {A : Set l} -> (p : A -> Bool) -> (xs : List A) -> length (filter p xs) ≤ℕ length xs ≡ true length-filter p [] = refl length-filter p (x :: xs) with p x ... | true = length-filter p xs ... | false = ≤ℕ-trans {length (filter p xs)} (length-filter p xs) (≤ℕ-suc (length xs))
-- filter-idem : ∀{l} {A : Set l} -> (p : A -> Bool) -> (xs : List A) -> filter p (filter p xs) ≡ filter p xs -- filter-idem p [] = refl -- filter-idem p (x :: xs) with keep (p x) -- ... | true , p' rewrite p' | p' filter-idem p xs = refl -- ... | false , p' rewrite p' = filter-idem p xs
variable A : Set
takeWhile : (p : A → Bool) → List A → List A takeWhile p [] = [] takeWhile p (x :: xs) with p x ... | true = x :: takeWhile p xs ... | false = []
replicate : ℕ → A → List A replicate zero _ = [] replicate (suc n) a = a :: replicate n a
takeWhile-tt : ∀ (x : A) (xs : List A) (p : A → Bool) → p x ≡ true → takeWhile p (x :: xs) ≡ x :: takeWhile p xs takeWhile-tt x xs p px rewrite px = refl
prop : (a : A) (n : ℕ) → (p : A → Bool) → p a ≡ true ------------------------------------- → takeWhile p (replicate n a) ≡ replicate n a prop a zero p _ = refl prop a (suc n) p pa rewrite prop a n p pa | takeWhile-tt a (replicate n a) p pa | prop a n p pa = refl