Fold-Fusion Strikes Back
Since I'm determined not to touch Agda after I get up in order to prepare for the midterms, I'm currently reluctant to fall asleep XD. Below I proved some simple facts about fold in Agda, but I haven't written any practical examples yet.
First we define function composition. The operator precedence "30" is arbitrarily chosen, which luckily seems to work.
infixl 30 _○_ _○_ : {A B C : Set} -> (B -> C) -> (A -> B) -> (A -> C) (f ○ g) x = f (g x)
Now we prove the Fold-Fusion Theorem. (By chain reasoning, of course. XD)
foldr-fusion : {α β γ : Set} -> {f : α -> β -> β} {e : β} {h : β -> γ} {g : α -> γ -> γ}-> ((x : α)(y : β) -> h (f x y) ≡ g x (h y)) -> ∀ (\xs -> (h ○ (foldr f e)) xs ≡ foldr g (h e) xs) foldr-fusion _ [] = refl foldr-fusion {_}{_}{_} {f}{e}{h}{g} fuse (x :: xs) = chain> (h ○ foldr f e) (x :: xs) === h (foldr f e (x :: xs)) by refl === h (f x (foldr f e xs)) by cong h refl === g x (h (foldr f e xs)) by fuse x (foldr f e xs) === g x ((h ○ foldr f e) xs) by cong (g x) refl === g x (foldr g (h e) xs) by cong (g x) (foldr-fusion fuse xs) === foldr g (h e) (x :: xs) by refl
This is the first time I formally prove the Fold-Fusion Theorem. XD
Define the identity fold and prove that it is indeed an identity.
id-foldr : {A : Set} -> List A -> List A id-foldr = foldr _::_ [] id-foldr-id : {A : Set}{xs : List A} -> id-foldr xs ≡ xs id-foldr-id {_}{[]} = refl id-foldr-id {_}{x :: xs} = chain> id-foldr (x :: xs) === foldr _::_ [] (x :: xs) by refl === x :: foldr _::_ [] xs by refl === x :: xs by cong (_::_ x) id-foldr-id
Then we prove that for any function f
, f
is the same as f ○ id-foldr
.
compose-id : {A B : Set}(f : List A -> B)(xs : List A) -> f xs ≡ (f ○ id-foldr) xs compose-id f xs = chain> f xs === f (id-foldr xs) by cong f (sym id-foldr-id) === (f ○ id-foldr) xs by refl
Finally we prove that map f
is a fold by Fold-Fusion Theorem: first add an id-foldr
to the right of map f
and then apply fold-fusion.
map-as-foldr : {A B : Set}{f : A -> B}{xs : List A} -> map f xs ≡ foldr (\y ys -> f y :: ys) [] xs map-as-foldr {A}{_}{f}{xs} = chain> map f xs === (map f ○ id-foldr) xs by compose-id (map f) xs === foldr (\y ys -> f y :: ys) [] xs by foldr-fusion fuse-cond xs where fuse-cond : (x : A)(xs : List A) -> (map f) (x :: xs) ≡ (\y ys -> f y :: ys) x (map f xs) fuse-cond x xs = refl
--
Chain reasoning is marvelous! XD
Labels: Agda, Programming
<< 回到主頁