{-# OPTIONS --without-K --exact-split --safe #-}

open import Fragment.Algebra.Signature

module Fragment.Algebra.Homomorphism.Base (Σ : Signature) where

open import Fragment.Algebra.Algebra Σ
open import Fragment.Algebra.Homomorphism.Definitions Σ

open import Fragment.Setoid.Morphism as Morphism
  hiding (id; ∣_∣; ∣_∣-cong)

open import Level using (Level; _⊔_)
open import Function using (_∘_; _$_)

open import Data.Vec using (map)
open import Data.Vec.Properties using (map-id; map-∘)
import Data.Vec.Relation.Binary.Equality.Setoid as VecSetoid

open import Relation.Binary using (IsEquivalence)
import Relation.Binary.Reasoning.Setoid as Reasoning

private
  variable
    a b c ℓ₁ ℓ₂ ℓ₃ : Level

module _
  (A : Algebra {a} {ℓ₁})
  (B : Algebra {b} {ℓ₂})
  where

  infixr 1 _⟿_

  record _⟿_ : Set (a  b  ℓ₁  ℓ₂) where
    field
      ∣_∣⃗    :  A ∥/≈   B ∥/≈
      ∣_∣-hom : Homomorphic A B (Morphism.∣_∣ ∣_∣⃗)

    ∣_∣ :  A    B 
    ∣_∣ = Morphism.∣_∣ ∣_∣⃗

    ∣_∣-cong : Congruent ≈[ A ] ≈[ B ] ∣_∣
    ∣_∣-cong = Morphism.∣_∣-cong ∣_∣⃗

open _⟿_ public

module _ {A : Algebra {a} {ℓ₁}} where

  private

    ∣id∣-hom : Homomorphic A A  x  x)
    ∣id∣-hom {n} f xs = A  f ⟧-cong $ reflexive (map-id xs)
      where open VecSetoid  A ∥/≈
            open IsEquivalence (≋-isEquivalence n) using (reflexive)

  id : A  A
  id = record { ∣_∣⃗    = Morphism.id
              ; ∣_∣-hom = ∣id∣-hom
              }

module _
  {A : Algebra {a} {ℓ₁}}
  {B : Algebra {b} {ℓ₂}}
  {C : Algebra {c} {ℓ₃}}
  (g : B  C)
  (f : A  B)
  where

  private

    ⊙-hom : Homomorphic A C ( g    f )
    ⊙-hom {n} op xs = begin
        C  op  (map ( g    f ) xs)
      ≈⟨ C  op ⟧-cong $ reflexive (map-∘  g   f  xs) 
        C  op  (map  g  (map  f  xs))
      ≈⟨  g ∣-hom op (map  f  xs) 
         g  (B  op  (map  f  xs))
      ≈⟨  g ∣-cong ( f ∣-hom op xs) 
         g  ( f  (A  op  xs))
      
      where open Reasoning  C ∥/≈
            open VecSetoid  C ∥/≈
            open IsEquivalence (≋-isEquivalence n) using (reflexive)

  infixr 9 _⊙_

  _⊙_ : A  C
  _⊙_ = record { ∣_∣⃗    =  g ∣⃗ ·  f ∣⃗
               ; ∣_∣-hom = ⊙-hom
               }