Last active
December 28, 2021 21:53
-
-
Save TOTBWF/f938f3fe702e766f74bf97f3e4760508 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {-# OPTIONS --without-K --safe #-} | |
| module InitialAlgebra where | |
| open import Level hiding (zero) renaming (suc to β-suc) | |
| open import Relation.Binary.PropositionalEquality.Core | |
| open import Data.Nat.Base using (β; zero; suc; _+_) | |
| open import Data.List.Base using (List; []; _β·_) | |
| open import Categories.Category | |
| open import Categories.Functor | |
| open import Categories.Functor.Algebra | |
| open import Categories.Category.Construction.F-Algebras | |
| open import Categories.Object.Initial | |
| open import Categories.Category.Instance.Sets | |
| -- First, let us fix a category π. | |
| module Inductives {o β e} (π : Category o β e) where | |
| open Category π | |
| -- We can give semantics to an inductive type as initial | |
| -- algebras for some endofunctor. | |
| record Inductive : Set (o β β β e) where | |
| field | |
| F : Endofunctor π | |
| Ο : F-Algebra F | |
| initial : IsInitial (F-Algebras F) Ο | |
| open Functor F public | |
| -- Let's rename some things to be a little more descriptive. | |
| -- We use 'roll' here to indicate that the | |
| -- F-Algebra Ο witnesses the fact that we can "roll up" a layer | |
| -- of recursion. | |
| open F-Algebra Ο renaming (A to Carrier; Ξ± to roll) public | |
| -- Furthermore, we use 'fold' here to emphasize that the map between | |
| -- F-Algebra carriers witnessed by 'initial' is indeed the fold we are looking for! | |
| -- We have to do some silly things with modules here because of some annoying implicits. | |
| open IsInitial initial public | |
| module Fold Ξ± = F-Algebra-Morphism (IsInitial.! initial {Ξ±}) renaming (f to fold; commutes to fold-commutes) | |
| open Fold public | |
| open Inductive public | |
| -- Now, for the heart of the matter! We are looking for a universal property | |
| -- that says that some map out of an inductive "is a fold". Really, something | |
| -- "is a fold" if it's an F-Algebra morphism out of the inductive type into | |
| -- /some/ other F-Algebra. | |
| -- By the uniqueness of the initial map, this means that our map 'f' is equal | |
| -- to 'fold'. | |
| record IsFold (T : Inductive) {A : Obj} (f : T .Carrier β A) : Set (β β e) where | |
| field | |
| -- This morphism, combined with 'A', forms an F-Algebra. | |
| alg : T .Fβ A β A | |
| -- This condition is just restating the commuting condition from 'F-Algebra-Morphism'. | |
| commutes : f β T .roll β alg β T .Fβ f | |
| -- The F-Algebra in question. | |
| Alg : F-Algebra (T .F) | |
| Alg = record { A = A ; Ξ± = alg } | |
| -- Bundle up the commuting condition along with the morphism on carriers to form an | |
| -- F-Algebra morphism. | |
| mor : F-Algebra-Morphism (T .Ο) Alg | |
| mor = record { f = f ; commutes = commutes } | |
| -- Show that 'f' is indeed equal to a fold for some algebra. | |
| is-fold : T .fold Alg β f | |
| is-fold = T .!-unique mor | |
| -- As an example, let's consider a concrete example: Lists. | |
| private module Example where | |
| -- Let's work over the Category of Sets. | |
| open Category (Sets 0β) | |
| open Inductives (Sets 0β) | |
| -- First, let's define smash products. | |
| data Smash (A B : Set) : Set where | |
| nada : Smash A B | |
| smash : A β B β Smash A B | |
| -- Next, let's witness the fact that 'Smash' is functorial | |
| -- in it's second argument. | |
| smash-map : β {A B C} β (B β C) β Smash A B β Smash A C | |
| smash-map f nada = nada | |
| smash-map f (smash a b) = smash a (f b) | |
| SMASH : Set β Endofunctor (Sets 0β) | |
| Functor.Fβ (SMASH A) = Smash A | |
| Functor.Fβ (SMASH A) = smash-map | |
| Functor.identity (SMASH A) {x = nada} = refl | |
| Functor.identity (SMASH A) {x = smash _ _} = refl | |
| Functor.homomorphism (SMASH A) {x = nada} = refl | |
| Functor.homomorphism (SMASH A) {x = smash _ _} = refl | |
| Functor.F-resp-β (SMASH A) eq {x = nada} = refl | |
| Functor.F-resp-β (SMASH A) eq {x = smash a _} = cong (smash a) eq | |
| -- We can construct a Smash-Algebra whose carrier is List. | |
| ListAlg : (A : Set) β F-Algebra (SMASH A) | |
| F-Algebra.A (ListAlg A) = List A | |
| F-Algebra.Ξ± (ListAlg A) nada = [] | |
| F-Algebra.Ξ± (ListAlg A) (smash x xs) = x β· xs | |
| open F-Algebra renaming (A to Carrier; Ξ± to β¦_β§) | |
| open F-Algebra-Morphism renaming (f to mor) | |
| -- Furthermore, given a Smash-Algebra, we can construct a map out of List | |
| -- into it's carrier | |
| list-fold : β {A} β (Ξ± : F-Algebra (SMASH A)) β List A β Ξ± .Carrier | |
| list-fold Ξ± [] = β¦ Ξ± β§ nada | |
| list-fold Ξ± (x β· xs) = β¦ Ξ± β§ (smash x (list-fold Ξ± xs)) | |
| -- Furthermore, list-fold commutes with it's associated algebra. | |
| list-fold-commutes : β {A} β (Ξ± : F-Algebra (SMASH A)) β list-fold Ξ± β β¦ ListAlg A β§ β β¦ Ξ± β§ β smash-map (list-fold Ξ±) | |
| list-fold-commutes Ξ± {nada} = refl | |
| list-fold-commutes Ξ± {smash x xs} = refl | |
| -- This means that list-fold is an F-Algebra Morphism. | |
| list-fold-mor : β {A} β (Ξ± : F-Algebra (SMASH A)) β F-Algebra-Morphism (ListAlg A) Ξ± | |
| mor (list-fold-mor Ξ±) = list-fold Ξ± | |
| commutes (list-fold-mor Ξ±) = list-fold-commutes Ξ± | |
| -- To make matters more interesting, 'list-fold-mor' witnesses initiality of 'ListAlg'. | |
| list-fold-unique : β {A} {Ξ± : F-Algebra (SMASH A)} β (f : F-Algebra-Morphism (ListAlg A) Ξ±) β F-Algebras (SMASH A) [ list-fold-mor Ξ± β f ] | |
| list-fold-unique f {[]} = sym (f .commutes {x = nada}) | |
| list-fold-unique f {x β· xs} rewrite list-fold-unique f {xs} = sym (f .commutes {x = smash x xs}) | |
| ListAlgInitial : β A β IsInitial (F-Algebras (SMASH A)) (ListAlg A) | |
| IsInitial.! (ListAlgInitial A) {Ξ±} = list-fold-mor Ξ± | |
| IsInitial.!-unique (ListAlgInitial A) = list-fold-unique | |
| -- All of this means that 'List' is an inductive type. | |
| LIST : Set β Inductive | |
| Inductives.Inductive.F (LIST A) = SMASH A | |
| Inductives.Inductive.Ο (LIST A) = ListAlg A | |
| Inductives.Inductive.initial (LIST A) = ListAlgInitial A | |
| -- With all of that categorical boilerplate out of the way, let's show that | |
| -- 'length is a fold. | |
| length : β {A : Set} β List A β β | |
| length [] = 0 | |
| length (_ β· xs) = suc (length xs) | |
| -- First, we define the associated F-Algebra. | |
| length-alg : β {A} β Smash A β β β | |
| length-alg nada = 0 | |
| length-alg (smash _ n) = suc n | |
| -- Next, we prove the commuting condition. | |
| length-commutes : β {A} β length β (LIST A) .roll β (length-alg β smash-map length) | |
| length-commutes {x = nada} = refl | |
| length-commutes {x = smash _ _} = refl | |
| -- Then that's it! | |
| length-is-fold : β {A} β IsFold (LIST A) length | |
| Inductives.IsFold.alg length-is-fold = length-alg | |
| Inductives.IsFold.commutes length-is-fold = length-commutes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment