{-# OPTIONS --rewriting #-}

-- Linear monoidal closed structure for families
module SOAS.Families.Linear {T : Set} where

open import SOAS.Common
open import SOAS.Context {T}
open import SOAS.Sorting {T}
open import SOAS.Families.Core {T}
open import SOAS.Families.Isomorphism {T}


open import Categories.Category.Monoidal
open import Categories.Category.Monoidal.Closed
open import Categories.Functor.Bifunctor

-- | Monoidal tensor and unit

-- Linear tensor product that combines two families with two disjoint contexts
data _⊗_ (X Y : Family) : Ctx  Set where
  merge : (Γ Δ : Ctx)  X Γ  Y Δ  (X  Y) (Δ  Γ)
infixr 20 _⊗_

pattern _⊹_ {Γ}{Δ} t s = merge Γ Δ t s
infix 30 _⊹_

-- ⊗ is a bifunctor
⊗F : Bifunctor 𝔽amilies 𝔽amilies 𝔽amilies
⊗F = record
  { F₀ = λ (X , Y)  X  Y
  ; F₁ = λ{ {X , Y}{X′ , Y′} (f , g) (x  y)  (f x)  (g y)}
  ; identity = λ{ {X , Y}{Γ}{x  y}  refl }
  ; homomorphism = λ{ {X , Y}{X′ , Y′}{X″ , Y″}{f , g}{f′ , g′}{Γ}{x  y}  refl }
  ; F-resp-≈ = λ{ (p₁ , p₂) {.(Δ  Γ)} {merge Γ Δ t s}  cong₂ (merge Γ Δ) p₁ p₂ }
  }

_⊗̣_ : Familyₛ  Familyₛ  Familyₛ
_⊗̣_ = sorted₂ _⊗_

𝒚 : Ctx  Family
𝒚 Γ Δ = Γ  Δ

-- Family which is only inhabited at the empty context
E : Family
E = 𝒚 

-- Sorted family which is only inhabited at a singleton context
N : Familyₛ
N α = 𝒚  α 

-- | Monoidal exponential

-- Linear exponential between families
_⊸_ : Family  Family  Family
(X  Y) Γ = {Δ : Ctx}  X Δ  Y (Δ  Γ)
infixr 15 _⊸_

-- Linear exponential between sorted families
_⊸∙_ : Familyₛ  Familyₛ  Familyₛ
_⊸∙_ = sorted₂ _⊸_
infixr 15 _⊸∙_

-- ⊸ is a bifunctor
⊸F : Bifunctor 𝔽am.op 𝔽amilies 𝔽amilies
⊸F = record
  { F₀ = λ (X , Y)  X  Y
  ; F₁ = λ{ {X , Y}{X′ , Y′} (f , g) e x  g (e (f x))}
  ; identity = refl
  ; homomorphism = refl
  ; F-resp-≈ = λ{ {X , Y}{X′ , Y′}{f , g} (p₁ , p₂) {Γ}{e} 
                      dext′ (trans (cong (g  e) p₁) p₂) }
  }


private variable X Y Z : Family

-- | Monoidal laws

-- Left unit
⊗-unitˡ : E  X ≅ₘ X
⊗-unitˡ = record
  { from = λ{ (refl  y)  y} ; to = λ y  refl  y
  ; iso = record { isoˡ = λ{ {Γ} {refl  y}  refl} ; isoʳ = refl } }

-- Right unit
⊗-unitʳ : (X  E) ≅ₘ X
⊗-unitʳ = record
  { from = λ{ (x  refl)  x} ; to = λ x  x  refl
  ; iso = record { isoˡ = λ{ {Γ} {x  refl}  refl} ; isoʳ = refl } }

-- Associativity
⊗-assoc : (X  Y)  Z ≅ₘ X  (Y  Z)
⊗-assoc = record
  { from = λ{ ((x  y)  z)  x  (y  z)} ; to = λ{ (x  (y  z))  (x  y)  z}
  ; iso = record { isoˡ = λ{ {Γ} {(x  y)  z}  refl}
                 ; isoʳ = λ{ {Γ} {x  (y  z)}  refl} } }

-- Monoidal structure on families via ⊗ and E
𝔽am:Monoidal : Monoidal 𝔽amilies
𝔽am:Monoidal = monoidalHelper 𝔽amilies (record
  {  = ⊗F
  ; unit = E
  ; unitorˡ = ⊗-unitˡ
  ; unitorʳ = ⊗-unitʳ
  ; associator = ⊗-assoc
  ; unitorˡ-commute = λ{ {X} {Y} {f} {_} {refl  y}  refl}
  ; unitorʳ-commute = λ{ {X} {Y} {f} {_} {x  refl}  refl}
  ; assoc-commute = λ{ {x = (x  y)  z}  refl}
  ; triangle = λ{ {x = (x  refl)  z}  refl}
  ; pentagon = λ{ {x = ((x  y)  z)  w}  refl }
  })


-- Categories of families is monoidal closed
𝔽am:MonClosed : Closed 𝔽am:Monoidal
𝔽am:MonClosed = record
  { [-,-] = ⊸F
  ; adjoint = λ {X}  record
    { unit = ntHelper (record { η = λ Y y x  y  x ; commute = λ f  refl })
    ; counit = ntHelper (record { η = λ{ Y (e  x)  e x} ; commute = λ{ {Y} {Z} f {_} {e  x}  refl} })
    ; zig = λ{ {Y} {_} {y  x}  refl}
    ; zag = refl
    }
  ; mate = λ f  record { commute₁ = refl ; commute₂ = λ{ {Z} {_} {e  x}  refl} }
  }
module 𝔽am:MonCl = Closed 𝔽am:MonClosed


-- | Sorted

-- Category of sorted families is monoidal closed
𝔽amₛ:Monoidal : Monoidal 𝔽amiliesₛ
𝔽amₛ:Monoidal = 𝕊orted-Monoidal 𝔽am:Monoidal

𝔽amₛ:MonClosed : Closed 𝔽amₛ:Monoidal
𝔽amₛ:MonClosed = 𝕊orted-MonClosed 𝔽am:MonClosed