module Cat.Functor.Algebra where
module _ {o ℓ} {C : Precategory o ℓ} (F : Functor C C) where
Algebras over an endofunctor🔗
Let be an arbitrary endofunctor on We can view as a means of embellishing an object with extra structure: for instance, the functor endows with an additional point and an endomap the functor adds an extra point and a copy of etc. Consequently, a map picks out a suitably structured e.g. writing a map requires to be equipped with a global element and an endomap In analogy to monad algebras, a map is called an F-algebra on 1.
Likewise, a map between two and is an F-algebra homomorphism if it commutes with the algebras on and as in the following digram.
Intuitively, morphisms are morphisms that preserve the structure encoded by going back to our previous example, an homomorphism between and is a map that preserves the designated global elements of and and commutes with the chosen endomaps.
We can assemble into a displayed category over the type of objects over consists of all possible algebra structures on and the type of morphisms over are proofs that is an homomorphism.
: Displayed C ℓ ℓ
F-Algebras .Ob[_] a = Hom (F.₀ a) a
F-Algebras .Hom[_] f α β = f ∘ α ≡ β ∘ F.₁ f
F-Algebras .Hom[_]-set _ _ _ = hlevel 2
F-Algebras .id' = idl _ ∙ intror F.F-id
F-Algebras ._∘'_ p q = pullr q ∙ pulll p ∙ pullr (sym (F.F-∘ _ _))
F-Algebras .idr' _ = prop!
F-Algebras .idl' _ = prop!
F-Algebras .assoc' _ _ _ = prop! F-Algebras
We can take the total category of this displayed category to recover the more traditional category of
: Precategory (o ⊔ ℓ) ℓ
FAlg = ∫ F-Algebras
FAlg
module FAlg = Cat.Reasoning FAlg
: Type _
F-Algebra = FAlg.Ob F-Algebra
Lambek’s lemma🔗
As noted above, are a tool for picking out objects equipped with a semantics for a “signature” described by This leads to a very natural question: can we characterize the syntax generated from the signature of
To answer this question, we must pin down exactly what we mean by “syntax”. Categorically, we have two options: initial objects, and free objects; these correspond to “syntax” and “syntax with generators”, respectively. We will focus initial for now: free objects are much harder to come by, and initial have a nice characterization: they are the least fixpoints of functors. This result is known as Lambek’s lemma, and we shall prove it now.
First, a tiny lemma. Let be an and note that is also an If has a section then and are inverses.
algebra-section→inverses: ∀ {a} (α : Hom (F.₀ a) a)
→ (f : FAlg.Hom (a , α) (F.₀ a , F.₁ α))
→ f .hom section-of α
→ Inverses α (f .hom)
=
algebra-section→inverses α f section
make-inverses section $.hom ∘ α ≡⟨ f .preserves ⟩
f .₁ α ∘ F.₁ (f .hom) ≡⟨ F.annihilate section ⟩
F id ∎
On to the main result. Let be an initial As before, is also an so initiality gives us a unique morphism Likewise, induces an morphism Furthermore, is a section of as maps out of the initial object are unique. Therefore, must also be an inverse, so is invertible.
: ∀ {a} (α : Hom (F.₀ a) a) → is-initial FAlg (a , α) → is-invertible α
lambek {a} α initial = inverses→invertible $
lambek
algebra-section→inverses α unroll roll-unrollwhere
: FAlg.Hom (a , α) (F.₀ a , F.₁ α)
unroll = initial (F.₀ a , F.₁ α) .centre
unroll
: FAlg.Hom (F.₀ a , F.₁ α) (a , α)
roll .hom = α
roll .preserves = refl
roll
: α ∘ unroll .hom ≡ id
roll-unroll =
roll-unroll
ap hom $(initial (a , α)) (roll FAlg.∘ unroll) FAlg.id is-contr→is-prop
This result means that an initial
is a fixpoint of the functor
and should be thought of as the the object
The canonical example is the initial algebra of
if it exists, this will be an object of the form
in
this initial algebra is the natural numbers! In general, initial
are how we give a categorical semantics to non-indexed inductive
datatypes like Nat
or List
.
Adámek’s fixpoint theorem🔗
Note that initial need not exist for a given functor Nevertheless, Adámek’s fixpoint theorem lets us construct some initial provided that:
- has an initial object.
- has a colimit for the diagram:
- preserves the aforementioned colimit.
Note that this construction is precisely a categorified version of Kleene’s fixpoint theorem, so we will be following the exact same proof strategy.
We begin by constructing the above diagram as a functor where is the poset of natural numbers, regarded as a category.
: Nat → Ob
F₀ⁿ[⊥] = bot
F₀ⁿ[⊥] zero (suc n) = F.₀ (F₀ⁿ[⊥] n)
F₀ⁿ[⊥]
: ∀ {m n} → m ≤ n → Hom (F₀ⁿ[⊥] m) (F₀ⁿ[⊥] n)
F₁ⁿ[⊥] = ¡
F₁ⁿ[⊥] 0≤x (s≤s p) = F.₁ (F₁ⁿ[⊥] p)
F₁ⁿ[⊥]
: Functor ω C Fⁿ[⊥]
Functoriality follows from some straightforward induction.
: ∀ n → F₁ⁿ[⊥] (≤-refl {n}) ≡ id
Fⁿ[⊥]-id = ¡-unique id
Fⁿ[⊥]-id zero (suc n) = F.elim (Fⁿ[⊥]-id n)
Fⁿ[⊥]-id
Fⁿ[⊥]-∘: ∀ {m n o}
→ (p : n ≤ o) (q : m ≤ n)
→ F₁ⁿ[⊥] (≤-trans q p) ≡ F₁ⁿ[⊥] p ∘ F₁ⁿ[⊥] q
= ¡-unique₂ _ _
Fⁿ[⊥]-∘ p 0≤x (s≤s p) (s≤s q) = F.expand (Fⁿ[⊥]-∘ p q)
Fⁿ[⊥]-∘
.F₀ = F₀ⁿ[⊥]
Fⁿ[⊥] .F₁ = F₁ⁿ[⊥]
Fⁿ[⊥] .F-id {n} = Fⁿ[⊥]-id n
Fⁿ[⊥] .F-∘ p q = Fⁿ[⊥]-∘ p q Fⁿ[⊥]
Next, note that every can be extended to a morphism Furthermore, this extension is natural in
: ∀ {a} → Hom (F.₀ a) a → ∀ n → Hom (F₀ⁿ[⊥] n) a
Fⁿ[⊥]-fold = ¡
Fⁿ[⊥]-fold α zero (suc n) = α ∘ F.₁ (Fⁿ[⊥]-fold α n)
Fⁿ[⊥]-fold α
Fⁿ[⊥]-fold-nat: ∀ {a} {α : Hom (F.₀ a) a} {m n}
→ (m≤n : m ≤ n)
→ Fⁿ[⊥]-fold α n ∘ F₁ⁿ[⊥] m≤n ≡ Fⁿ[⊥]-fold α m
= sym (¡-unique _)
Fⁿ[⊥]-fold-nat 0≤x (s≤s m≤n) = F.pullr (Fⁿ[⊥]-fold-nat m≤n) Fⁿ[⊥]-fold-nat
Now, suppose that has a colimit of the diagram and preserves this colimit. We can equip with an by using the universal property of the colimit
: Colimit Fⁿ[⊥] → preserves-colimit F Fⁿ[⊥] → Initial FAlg
adamek = ∐Fⁿ[⊥]-initial
adamek Fⁿ[⊥]-colim F-pres-Fⁿ[⊥]-colim module adamek where
module ∐Fⁿ[⊥] = Colimit Fⁿ[⊥]-colim
module F[∐Fⁿ[⊥]] = is-colimit (F-pres-Fⁿ[⊥]-colim ∐Fⁿ[⊥].has-colimit)
: Ob
∐Fⁿ[⊥] = ∐Fⁿ[⊥].coapex
∐Fⁿ[⊥]
: Hom (F.₀ ∐Fⁿ[⊥]) ∐Fⁿ[⊥]
roll = F[∐Fⁿ[⊥]].universal (∐Fⁿ[⊥].ψ ⊙ suc) (∐Fⁿ[⊥].commutes ⊙ s≤s) roll
Next, we can extend any F-algebra to a morphism by using the universal property, along with the extensions we constructed earlier.
: ∀ {a} → Hom (F.₀ a) a → Hom ∐Fⁿ[⊥] a
fold = ∐Fⁿ[⊥].universal (Fⁿ[⊥]-fold α) Fⁿ[⊥]-fold-nat fold α
This extension commutes with and thus induces an morphism
: ∀ {a} (α : Hom (F.₀ a) a) → fold α ∘ roll ≡ α ∘ F.₁ (fold α)
fold-roll =
fold-roll α .unique₂ (Fⁿ[⊥]-fold α ⊙ suc) (Fⁿ[⊥]-fold-nat ⊙ s≤s)
F[∐Fⁿ[⊥]](λ j →
(fold α ∘ roll) ∘ F.₁ (∐Fⁿ[⊥].ψ j) ≡⟨ pullr (F[∐Fⁿ[⊥]].factors _ _) ⟩
.ψ (suc j) ≡⟨ ∐Fⁿ[⊥].factors _ _ ⟩
fold α ∘ ∐Fⁿ[⊥](suc j) ∎)
Fⁿ[⊥]-fold α (λ j →
(α ∘ F.₁ (fold α)) ∘ F.₁ (∐Fⁿ[⊥].ψ j) ≡⟨ F.pullr (∐Fⁿ[⊥].factors _ _) ⟩
.F₁ (Fⁿ[⊥]-fold α j) ∎) α ∘ F
Furthermore, this extension is unique: this follows from a quick induction paired with the universal property of
fold-step: ∀ {a} {α : Hom (F.₀ a) a}
→ (f : Hom ∐Fⁿ[⊥] a)
→ f ∘ roll ≡ α ∘ F.₁ f
→ ∀ n → f ∘ ∐Fⁿ[⊥].ψ n ≡ Fⁿ[⊥]-fold α n
{α = α} f p zero = sym (¡-unique _)
fold-step {α = α} f p (suc n) =
fold-step .ψ (suc n) ≡˘⟨ ap (f ∘_) (F[∐Fⁿ[⊥]].factors _ _) ⟩
f ∘ ∐Fⁿ[⊥].F₁ (∐Fⁿ[⊥].ψ n) ≡⟨ pulll p ⟩
f ∘ roll ∘ F(α ∘ F.F₁ f) ∘ F.F₁ (∐Fⁿ[⊥].ψ n) ≡⟨ F.pullr (fold-step f p n) ⟩
.₁ (Fⁿ[⊥]-fold _ n) ∎
α ∘ F
fold-unique: ∀ {a} {α : Hom (F.₀ a) a}
→ (f : Hom ∐Fⁿ[⊥] a)
→ f ∘ roll ≡ α ∘ F.₁ f
→ fold α ≡ f
= sym $ ∐Fⁿ[⊥].unique _ _ _ (fold-step f p) fold-unique f p
If we put all the pieces together, we observe that is an initial
: Initial FAlg
∐Fⁿ[⊥]-initial .Initial.bot .fst = ∐Fⁿ[⊥]
∐Fⁿ[⊥]-initial .Initial.bot .snd = roll
∐Fⁿ[⊥]-initial .Initial.has⊥ (a , α) .centre .hom = fold α
∐Fⁿ[⊥]-initial .Initial.has⊥ (a , α) .centre .preserves = fold-roll α
∐Fⁿ[⊥]-initial .Initial.has⊥ (a , α) .paths f =
∐Fⁿ[⊥]-initial (fold-unique (f .hom) (f .preserves)) prop! total-hom-path F-Algebras
Free algebras and free monads🔗
In the previous section, we dismissed free as somewhat rare objects. It is now time to see why this is the case. Suppose that has all free this is equivalent to requiring a left adjoint to the functor that forgets
module _ {Free : Functor C FAlg} (Free⊣π : Free ⊣ πᶠ F-Algebras) where
private
module Free = Cat.Functor.Reasoning Free
open _⊣_ Free⊣π
open Functor
This adjunction induces a monad on which we will call the algebraically free monad on
: Monad C
Alg-free-monad = Adjunction→Monad Free⊣π Alg-free-monad
That was pretty abstract, so let’s unpack the data we have on hand. The left adjoint takes each object to an object that is equipped with an
private
: Ob → Ob
F* = Free.₀ x .fst
F* x
: ∀ (x : Ob) → Hom (F.₀ (F* x)) (F* x)
roll = Free.₀ x .snd roll x
Furthermore, the left adjoint takes each to an homomorphism as in the following diagram:
: ∀ {a b} → Hom a b → Hom (F* a) (F* b)
map* = Free.₁ f .hom
map* f
: ∀ {a b} (f : Hom a b) → map* f ∘ roll a ≡ roll b ∘ F.₁ (map* f)
map*-roll = Free.₁ f .preserves map*-roll f
The counit of our adjunction lets us extend any to an Intuitively, this operation lets us eliminate out of the fixpoint by describing how to eliminate out of each layer.
: ∀ {a} → Hom (F.₀ a) a → Hom (F* a) a
fold {a} α = counit.ε (a , α) .hom
fold
: ∀ {a} (α : Hom (F.₀ a) a) → fold α ∘ roll a ≡ α ∘ F.₁ (fold α)
fold-roll {a} α = counit.ε (a , α) .preserves fold-roll
Extending gives us the multiplication of the monad.
: ∀ (x : Ob) → Hom (F* (F* x)) (F* x)
mult = fold (roll x) mult x
We can also determine the equality of morphisms purely based off of how they behave on points.
fold-ext: ∀ {a b}
→ (f g : FAlg.Hom (Free.₀ a) b)
→ (f .hom ∘ unit.η _ ≡ g .hom ∘ unit.η _)
→ f .hom ≡ g .hom
=
fold-ext f g p .injective (_ , L-adjunct-is-equiv Free⊣π) {x = f} {y = g} $
ap hom $ Equiv p
Note that any yields an algebra for the algebraically free monad via extension along
: ∀ {a} → Hom (F.₀ a) a → Algebra-on C Alg-free-monad a
lift-alg {a = a} α .ν = fold α
lift-alg {a = a} α .ν-unit = zag
lift-alg {a = a} α .ν-mult =
lift-alg .is-natural (Free.₀ a) (a , α) (counit.ε (a , α)) ap hom $ counit
Likewise, we can extract an out of a monad algebra by precomposing with intuitively, this lifts into by adding on zero extra layers, and then passes it off to the monad algebra to be eliminated.
: ∀ {a} → Algebra-on C Alg-free-monad a → Hom (F.₀ a) a
lower-alg {a = a} α = α .ν ∘ roll a ∘ F.₁ (unit.η a) lower-alg
We can also view a monad algebra as a morphism of as described in the following digram:
This diagram states that we should be able to eliminate a either by rolling in the and passing the resulting off to the monad algebra, or by eliminating the inner first, and then evaluating the remaining Intuitively, this is quite clear, but proving it involves quite a bit of algebra.
alg*: ∀ {a} → (α : Algebra-on C Alg-free-monad a)
→ FAlg.Hom (F* a , roll a) (a , (α .ν ∘ roll a ∘ F.₁ (unit.η a)))
{a = a} α .hom = α .ν
alg* {a = a} α .preserves =
alg* .ν ∘ roll a ≡⟨ intror (F.annihilate zag) ⟩
α (α .ν ∘ roll a) ∘ (F.₁ (mult a) ∘ F.₁ (unit.η _)) ≡⟨ pull-inner (sym $ fold-roll (roll a)) ⟩
.ν ∘ (mult a ∘ roll (F* a)) ∘ F.₁ (unit.η _) ≡⟨ dispersel (sym $ α .ν-mult) ⟩
α .ν ∘ Free.₁ (α .ν) .hom ∘ roll (F* a) ∘ F.₁ (unit.η _) ≡⟨ extend-inner (map*-roll (α .ν)) ⟩
α .ν ∘ roll a ∘ F.₁ (map* (α .ν)) ∘ F.₁ (unit.η _) ≡⟨ centralizer (F.weave (sym (unit.is-natural _ _ _))) ⟩
α .ν ∘ (roll a ∘ F.₁ (unit.η _)) ∘ F.₁ (α .ν) ≡⟨ assoc _ _ _ ⟩
α (α .ν ∘ roll a ∘ F.₁ (unit.η _)) ∘ F.₁ (α .ν) ∎
However, this algebra pays off, as it lets us establish an equivalence between and algebras over the algebraically free monad on
: ∀ a → Hom (F.₀ a) a ≃ Algebra-on C Alg-free-monad a
f-algebra≃free-monad-algebra = Iso→Equiv $
f-algebra≃free-monad-algebra a
lift-alg , iso lower-alg(Algebra-on-pathp C refl ⊙ equivl)
equivrwhere
equivl: ∀ {a} (α : Algebra-on C Alg-free-monad a)
→ counit.ε (a , lower-alg α) .hom ≡ α .ν
=
equivl α (counit.ε _) (alg* α) $ zag ∙ sym (α .ν-unit)
fold-ext
equivr: ∀ {a} (α : Hom (F.₀ a) a)
→ counit.ε (a , α) .hom ∘ roll a ∘ F.₁ (unit.η _) ≡ α
{a} α =
equivr (counit.ε (a , α) .preserves) ∙ F.cancelr zag pulll
Likewise, we have an equivalence between morphisms and monad algebra morphisms.
private module Free-EM = Cat.Reasoning (Eilenberg-Moore C Alg-free-monad)
lift-alg-hom: ∀ {a b} {α β}
→ FAlg.Hom (a , α) (b , β)
→ Free-EM.Hom (a , lift-alg α) (b , lift-alg β)
.morphism = f .hom
lift-alg-hom f .commutes =
lift-alg-hom f (sym $ ap hom $ counit.is-natural _ _ f)
lower-alg-hom: ∀ {a b} {α β}
→ Free-EM.Hom (a , lift-alg α) (b , lift-alg β)
→ FAlg.Hom (a , α) (b , β)
.hom = f .morphism
lower-alg-hom f {a} {b} {α} {β} f .preserves =
lower-alg-hom .morphism ∘ α ≡⟨ ap₂ _∘_ refl (insertr (F.annihilate zag)) ⟩
f .morphism ∘ (α ∘ F.₁ (ε (a , α) .hom)) ∘ F.₁ (η a) ≡⟨ push-inner (sym (fold-roll α)) ⟩
f .morphism ∘ ε (a , α) .hom ⌝ ∘ (roll a ∘ F.₁ (η a)) ≡⟨ ap! (f .commutes) ⟩
⌜ f (ε (b , β) .hom ∘ Free.F₁ (f .morphism) .hom) ∘ (roll a ∘ F.₁ (η a)) ≡⟨ pull-inner (map*-roll (f .morphism)) ⟩
(b , β) .hom ∘ (roll b ∘ F.₁ (map* (f .morphism))) ∘ F.₁ (η a) ≡⟨ disperse (fold-roll β) (F.weave (sym (unit.is-natural _ _ _))) ⟩
ε .₁ (ε (b , β) .hom) ∘ F.₁ (η b) ∘ F.₁ (f .morphism) ≡⟨ ap₂ _∘_ refl (cancell (F.annihilate zag)) ⟩
β ∘ F(F.₁ (f .morphism)) ∎ β ∘
Therefore, we have an isomorphism of precategories between the category of and the Eilenberg-Moore category of the monad we constructed, giving us the appropriate universal property for an algebraically free monad.
FAlg→Free-EM: Functor FAlg (Eilenberg-Moore C Alg-free-monad)
.F₀ (a , α) =
FAlg→Free-EM
a , lift-alg α.F₁ = lift-alg-hom
FAlg→Free-EM .F-id = ext refl
FAlg→Free-EM .F-∘ f g = ext refl
FAlg→Free-EM
: is-precat-iso FAlg→Free-EM
FAlg≅Free-EM .is-precat-iso.has-is-ff =
FAlg≅Free-EM
is-iso→is-equiv $ iso lower-alg-hom(λ _ → trivial!)
(λ _ → total-hom-path F-Algebras refl prop!)
.is-precat-iso.has-is-iso =
FAlg≅Free-EM .snd Σ-ap-snd f-algebra≃free-monad-algebra
Free algebras and free relative monads🔗
The previous construction of the algebraically free monad on only works if we have all free This is a rather strong condition on what can we do in the general setting?
First, note that the category of objects equipped with free forms a full subcategory of
: Precategory _ _
Free-algebras = Restrict {C = C} (Free-object (πᶠ F-Algebras))
Free-algebras
: Functor Free-algebras C
Free-algebras↪C = Forget-full-subcat Free-algebras↪C
If we restrict along the inclusion from this category, we can construct the free relative extension system on Unlike the algebraically free monad on this extension system always exists, though it may be trivial if lacks any free algebras.
: Relative-extension-system Free-algebras↪C
Free-relative-extension .M₀ α =
Free-relative-extension .ob α
Free-alg.unit {α} =
Free-relative-extension .unit α
Free-alg.bind {α} {β} f =
Free-relative-extension .fold α {Free-alg.free β} f .hom
Free-alg.bind-unit-id {α} =
Free-relative-extension .fold-unit α
ap hom $ Free-alg.bind-unit-∘ {α} {β} f =
Free-relative-extension .commute α
Free-alg.bind-∘ {α} {β} {γ} f g = ap hom $
Free-relative-extension .fold β f FAlg.∘ Free-alg.fold α g ≡˘⟨ Free-alg.fold-natural α (Free-alg.fold β f) g ⟩
Free-alg.fold α (Free-alg.fold β f .hom ∘ g) ∎ Free-alg
Alternatively, we can view as monad algebras over functors that lack algebraic structure.↩︎