{-# OPTIONS --without-K --exact-split --safe #-} open import Fragment.Algebra.Signature module Fragment.Algebra.Free.Monad (Σ : Signature) where open import Fragment.Algebra.Free.Base Σ open import Fragment.Algebra.Algebra Σ open import Fragment.Algebra.Homomorphism Σ using (_⟿_; Congruent; Homomorphic) open import Fragment.Setoid.Morphism open import Level using (Level) open import Data.Vec using (Vec; []; _∷_; map) open import Data.Vec.Relation.Binary.Pointwise.Inductive using (Pointwise; []; _∷_) open import Relation.Binary using (Setoid) private variable a b ℓ₁ ℓ₂ : Level unit : ∀ {S : Setoid a ℓ₁} → S ↝ Herbrand S unit = record { ∣_∣ = atom ; ∣_∣-cong = atom } module _ {A : Setoid a ℓ₁} {B : Setoid b ℓ₂} (f : A ↝ Herbrand B) where private open Setoid ∥ Free B ∥/≈ module _ {A : Set a} {B : Set b} where mutual map-∣bind∣ : ∀ {n} → (A → Term B) → Vec (Term A) n → Vec (Term B) n map-∣bind∣ f [] = [] map-∣bind∣ f (x ∷ xs) = ∣bind∣ f x ∷ map-∣bind∣ f xs ∣bind∣ : (A → Term B) → Term A → Term B ∣bind∣ f (atom x) = f x ∣bind∣ f (term op xs) = term op (map-∣bind∣ f xs) mutual map-∣bind∣-cong : ∀ {n} {xs ys : Vec ∥ Free A ∥ n} → Pointwise (_~_ A) xs ys → Pointwise (_~_ B) (map-∣bind∣ ∣ f ∣ xs) (map-∣bind∣ ∣ f ∣ ys) map-∣bind∣-cong [] = [] map-∣bind∣-cong (p ∷ ps) = ∣bind∣-cong p ∷ map-∣bind∣-cong ps ∣bind∣-cong : Congruent (_~_ A) (_~_ B) (∣bind∣ ∣ f ∣) ∣bind∣-cong (atom p) = ∣ f ∣-cong p ∣bind∣-cong {x = term op _} (term p) = term (map-∣bind∣-cong p) map-∣bind∣≡map : ∀ {n} {xs : Vec ∥ Free A ∥ n} → Pointwise (_~_ B) (map-∣bind∣ ∣ f ∣ xs) (map (∣bind∣ ∣ f ∣) xs) map-∣bind∣≡map {xs = []} = [] map-∣bind∣≡map {xs = x ∷ xs} = refl ∷ map-∣bind∣≡map ∣bind∣-hom : Homomorphic (Free A) (Free B) (∣bind∣ ∣ f ∣) ∣bind∣-hom op [] = refl ∣bind∣-hom op (x ∷ xs) = sym (term (map-∣bind∣≡map {xs = x ∷ xs})) ∣bind∣⃗ : Herbrand A ↝ Herbrand B ∣bind∣⃗ = record { ∣_∣ = ∣bind∣ ∣ f ∣ ; ∣_∣-cong = ∣bind∣-cong } bind : Free A ⟿ Free B bind = record { ∣_∣⃗ = ∣bind∣⃗ ; ∣_∣-hom = ∣bind∣-hom } fmap : ∀ {A : Setoid a ℓ₁} {B : Setoid b ℓ₂} → A ↝ B → Free A ⟿ Free B fmap f = bind (unit · f) join : ∀ {A : Setoid a ℓ₁} → Free (Herbrand A) ⟿ Free A join = bind id