Martin Escardo, Paulo Oliva, May 2024

\begin{code}

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

open import Notation.General
open import MLTT.Spartan
open import UF.Equiv
open import UF.FunExt
open import RelativeMonadOnStructuredTypes.OneSigmaStructure

module RelativeMonadOnStructuredTypes.Definition
        {{ρ : πŸ™-Ξ£-structure}}
       where

open πŸ™-Ξ£-structure ρ

record Relative-Monad {β„“ : Universe β†’ Universe} : 𝓀ω where
 field
  functor : {𝓀 : Universe} β†’ π•Š 𝓀 β†’ β„“ 𝓀 Μ‡

 private
  T = functor

 field
  Ξ·       : {𝓀 : Universe} {𝓧 : π•Š 𝓀}
          β†’ ⟨ 𝓧 ⟩ β†’ T 𝓧
  ext     : {𝓀 π“₯ : Universe} {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯}
          β†’ (⟨ 𝓧 ⟩ β†’ T 𝓨)
          β†’ T 𝓧 β†’ T 𝓨
  ext-Ξ·   : {𝓀 : Universe} {𝓧 : π•Š 𝓀}
          β†’ ext (Ξ· {𝓀} {𝓧}) ∼ 𝑖𝑑 (T 𝓧)
  unit    : {𝓀 π“₯ : Universe} {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯}
            (f : ⟨ 𝓧 ⟩ β†’ T 𝓨)
            (x : ⟨ 𝓧 ⟩)
          β†’ ext {𝓀} {π“₯} {𝓧} {𝓨} f (Ξ· x) = f x
  assoc   : {𝓀 π“₯ 𝓦 : Universe}
            {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯} {𝓩 : π•Š 𝓦}
            (g : ⟨ 𝓨 ⟩ β†’ T 𝓩)
            (f : ⟨ 𝓧 ⟩ β†’ T 𝓨)
            (t : T 𝓧)
          β†’ ext (Ξ» x β†’ ext g (f x)) t = ext g (ext f t)

 map : {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯} β†’ (⟨ 𝓧 ⟩ β†’ ⟨ 𝓨 ⟩) β†’ T 𝓧 β†’ T 𝓨
 map f = ext (η ∘ f)

 _βŠ—α΅£_ : {𝓧 : π•Š 𝓀} {𝓨 : ⟨ 𝓧 ⟩ β†’ π•Š π“₯}
      β†’ T 𝓧
      β†’ ((x : ⟨ 𝓧 ⟩) β†’ T (𝓨 x))
      β†’ T (Ξ£β‚› x κž‰ 𝓧 , 𝓨 x)
 t βŠ—α΅£ f = ext (Ξ» x β†’ map (Ξ» y β†’ x , y) (f x)) t

open Relative-Monad public

\end{code}

TODO. Is "tensor" an appropriate terminology? Would (left)
convolution, in the sense of Day, be better?

    https://ncatlab.org/nlab/show/tensorial+strength
    https://ncatlab.org/nlab/show/Day+convolution

\begin{code}

tensorα΅£ : {β„“ : Universe β†’ Universe}
          (𝕋 : Relative-Monad {β„“})
          {𝓧 : π•Š 𝓀} {𝓨 : ⟨ 𝓧 ⟩ β†’ π•Š π“₯}
        β†’ functor 𝕋 𝓧
        β†’ ((x : ⟨ 𝓧 ⟩) β†’ functor 𝕋 (𝓨 x))
        β†’ functor 𝕋 (Ξ£β‚› x κž‰ 𝓧 , 𝓨 x)
tensorα΅£ 𝕋 = _βŠ—α΅£_ 𝕋

syntax tensorα΅£ 𝕋 t f = t βŠ—α΅£[ 𝕋 ] f

\end{code}

If we want to call a Relative-Monad T, then we can use the following
module:

\begin{code}

module relative-T-definitions
        {β„“ : Universe β†’ Universe}
        (𝕋 : Relative-Monad {β„“})
       where

 T : {𝓀 : Universe}
   β†’ π•Š 𝓀 β†’ β„“ 𝓀 Μ‡
 T {𝓀} = functor 𝕋

 Ξ·α΅€ : {𝓧 : π•Š 𝓀}
    β†’ ⟨ 𝓧 ⟩ β†’ T 𝓧
 Ξ·α΅€ = Ξ· 𝕋

 extα΅€ : {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯}
      β†’ (⟨ 𝓧 ⟩ β†’ T 𝓨) β†’ T 𝓧 β†’ T 𝓨
 extα΅€ = ext 𝕋

 extα΅€-Ξ· : {𝓧 : π•Š 𝓀} β†’ extα΅€ (Ξ·α΅€ {𝓀} {𝓧}) ∼ 𝑖𝑑 (T 𝓧)
 extα΅€-Ξ· = ext-Ξ· 𝕋

 unitα΅€ : {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯} (f : ⟨ 𝓧 ⟩ β†’ T 𝓨)
       β†’ extα΅€ {𝓀} {π“₯} {𝓧} {𝓨} f ∘ Ξ·α΅€ ∼ f
 unitα΅€ = unit 𝕋

 assocα΅€ : {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯} {𝓩 : π•Š 𝓦}
          (g : ⟨ 𝓨 ⟩ β†’ T 𝓩) (f : ⟨ 𝓧 ⟩ β†’ T 𝓨)
        β†’ extα΅€ {_} {_} {𝓧} {𝓩} (extα΅€ g ∘ f) ∼ extα΅€ g ∘ extα΅€ f
 assocα΅€ = assoc 𝕋

 mapα΅€ : {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯} β†’ (⟨ 𝓧 ⟩ β†’ ⟨ 𝓨 ⟩) β†’ T 𝓧 β†’ T 𝓨
 mapα΅€ = map 𝕋

 _βŠ—α΅€_ : {𝓧 : π•Š 𝓀} {𝓨 : ⟨ 𝓧 ⟩ β†’ π•Š π“₯}
      β†’ T 𝓧
      β†’ ((x : ⟨ 𝓧 ⟩) β†’ T (𝓨 x))
      β†’ T (Ξ£β‚› x κž‰ 𝓧 , 𝓨 x)
 _βŠ—α΅€_ = _βŠ—α΅£_ 𝕋

\end{code}

For some results, we need our monad to satisfy the condition
extα΅€-const defined below. Ohad Kammar pointed out to us that this
condition is equivalent to the monad being affine. We include his
proof here.

References given by Ohad Kammar and Alex Simpson:

[1] Anders Kock, Bilinearity and Cartesian closed monads,
Math. Stand. 29 (1971) 161-174.
https://users-math.au.dk/kock/BCCM.pdf

[2]
https://www.denotational.co.uk/publications/kammar-plotkin-algebraic-foundations-for-effect-dependent-optimisations.pdf

[3] https://www.denotational.co.uk/publications/kammar-ohad-thesis.pdf

[4] Gavin Wraith mentions affine theories in his lecture notes form
1969 (Prop. 3.5 here:
https://www.denotational.co.uk/scans/wraith-algebraic-theories.pdf)

[5] Bart Jacobs' "Semantics of weakening and contraction".
https://doi.org/10.1016/0168-0072(94)90020-5

\begin{code}

module _ {β„“ : Universe β†’ Universe}
         (𝕋 : Relative-Monad {β„“})
       where

 open relative-T-definitions 𝕋

 is-affine : 𝓀ω
 is-affine = {𝓀 : Universe} β†’ is-equiv (Ξ·α΅€ {𝓀} {πŸ™β‚›})

 ext-const' : π•Š 𝓀 β†’ 𝓀ω
 ext-const' 𝓧 = {π“₯ : Universe} {𝓨 : π•Š π“₯} (u : T 𝓨)
                       β†’ extα΅€ (Ξ» (x : ⟨ 𝓧 ⟩) β†’ u) ∼ Ξ» (t : T 𝓧) β†’ u
  where
   remark : {π“₯ : Universe} {𝓨 : π•Š π“₯} (u : T 𝓨) β†’ functor 𝕋 𝓧 β†’ functor 𝕋 𝓨
   remark u = extα΅€ (Ξ» (x : ⟨ 𝓧 ⟩) β†’ u)

 ext-const : 𝓀ω
 ext-const = {𝓀 : Universe} {𝓧 : π•Š 𝓀} β†’ ext-const' 𝓧

 affine-gives-ext-const' : Fun-Ext β†’ is-affine β†’ ext-const' (πŸ™β‚› {𝓀})
 affine-gives-ext-const' {𝓀} fe a {𝓨} u t = Ξ³
  where
   f = Ξ» (x : πŸ™) β†’ u

   I : f ∘ inverse (Ξ·α΅€ {𝓀} {πŸ™β‚›}) a ∼ extα΅€ f
   I s = (f ∘ inverse Ξ·α΅€ a) s         =⟨ Iβ‚€ ⟩
         extα΅€ f (Ξ·α΅€ (inverse Ξ·α΅€ a s)) =⟨ I₁ ⟩
         extα΅€ f s                     ∎
    where
     Iβ‚€ = (unitα΅€ f (inverse Ξ·α΅€ a s))⁻¹
     I₁ = ap (extα΅€ f) (inverses-are-sections Ξ·α΅€ a s)

   Ξ³ : extα΅€ f t = u
   Ξ³ = extα΅€ f t                        =⟨ (ap (Ξ» - β†’ - t) (dfunext fe I))⁻¹ ⟩
       (f ∘ inverse (Ξ·α΅€ {𝓀} {πŸ™β‚›}) a) t =⟨refl⟩
       u                               ∎

 affine-gives-ext-const : Fun-Ext β†’ is-affine β†’ ext-const
 affine-gives-ext-const fe a {𝓀} {𝓧} {π“₯} {𝓨} u t = Ξ³
  where
   g : ⟨ 𝓧 ⟩ β†’ T 𝓨
   g _ = u

   f : T πŸ™β‚› β†’ T 𝓨
   f _ = u

   h : πŸ™ β†’ T 𝓨
   h _ = u

   k : ⟨ 𝓧 ⟩ β†’ T πŸ™β‚›
   k = Ξ·α΅€ {𝓀} {πŸ™β‚›} ∘ unique-to-πŸ™

   I : extα΅€ h = f
   I = dfunext fe (affine-gives-ext-const' fe a u)

   Ξ³ = extα΅€ g t             =⟨refl⟩
       extα΅€ (f ∘ k) t       =⟨ ap (Ξ» - β†’ extα΅€ (- ∘ k) t) (I ⁻¹) ⟩
       extα΅€ (extα΅€ h ∘ k) t  =⟨ assocα΅€ h k t ⟩
       extα΅€ h (extα΅€ k t)    =⟨ ap (Ξ» - β†’ - (extα΅€ k t)) I ⟩
       f (extα΅€ k t)         =⟨refl⟩
       u                    ∎

 ext-const-gives-affine : ext-const β†’ is-affine
 ext-const-gives-affine Ο• {𝓀} = Ξ³
  where
   η⁻¹ : T πŸ™β‚› β†’ πŸ™
   η⁻¹ t = ⋆

   I : η⁻¹ ∘ Ξ·α΅€ ∼ id
   I ⋆ = refl

   II : Ξ·α΅€ ∘ η⁻¹ ∼ id
   II t = (Ξ·α΅€ ∘ η⁻¹) t        =⟨refl⟩
          Ξ·α΅€ ⋆                =⟨ (Ο• {𝓀} {πŸ™β‚›} (Ξ·α΅€ ⋆) t)⁻¹ ⟩
          extα΅€ (Ξ» x β†’ Ξ·α΅€ ⋆) t =⟨refl⟩
          extα΅€ Ξ·α΅€ t           =⟨ extα΅€-Ξ· t ⟩
          t                   ∎

   Ξ³ : is-equiv (Ξ·α΅€ {𝓀} {πŸ™β‚›})
   Ξ³ = qinvs-are-equivs Ξ·α΅€ (η⁻¹ , I , II)

\end{code}

Relative-Monad algebras.

\begin{code}

record Relative-Algebra
        {𝓦₀ : Universe}
        {β„“ : Universe β†’ Universe}
        (𝕋 : Relative-Monad {β„“})
        (R : 𝓦₀ Μ‡ ) : 𝓀ω where
 field
  aext     : {𝓀 : Universe} {𝓧 : π•Š 𝓀}
           β†’ (⟨ 𝓧 ⟩ β†’ R)
           β†’ functor 𝕋 𝓧 β†’ R
  aunit    : {𝓀 : Universe} {𝓧 : π•Š 𝓀}
             (f : ⟨ 𝓧 ⟩ β†’ R)
             (x : ⟨ 𝓧 ⟩)
           β†’ aext {𝓀} {𝓧} f (Ξ· 𝕋 x) = f x
  aassoc   : {𝓀 π“₯ : Universe}
             {𝓧 : π•Š 𝓀} {𝓨 : π•Š π“₯}
             (g : ⟨ 𝓨 ⟩ β†’ R)
             (f : ⟨ 𝓧 ⟩ β†’ functor 𝕋 𝓨)
             (t : functor 𝕋 𝓧)
           β†’ aext (Ξ» x β†’ aext g (f x)) t = aext g (ext 𝕋 f t)

open Relative-Algebra public

\end{code}

If we want to call an algebra (literally) Ξ±, we can used this module:

\begin{code}

module relative-Ξ±-definitions
        {β„“ : Universe β†’ Universe}
        (𝕋 : Relative-Monad {β„“})
        {𝓦₀ : Universe}
        (𝓑 : π•Š 𝓦₀)
        (𝓐 : Relative-Algebra {𝓦₀} {β„“} 𝕋 ⟨ 𝓑 ⟩)
       where

 open relative-T-definitions 𝕋

 Ξ± : T 𝓑 β†’ ⟨ 𝓑 ⟩
 Ξ± = aext 𝓐 id

 Ξ±-unitα΅€ : Ξ± ∘ Ξ·α΅€ ∼ id
 Ξ±-unitα΅€ = aunit 𝓐 id

 extᴬ : {𝓧 : π•Š 𝓀} β†’ (⟨ 𝓧 ⟩ β†’ ⟨ 𝓑 ⟩) β†’ T 𝓧 β†’ ⟨ 𝓑 ⟩
 extᴬ = aext 𝓐

 extᴬ-alternative : {𝓧 : π•Š 𝓀} β†’ (⟨ 𝓧 ⟩ β†’ ⟨ 𝓑 ⟩) β†’ T 𝓧 β†’ ⟨ 𝓑 ⟩
 extᴬ-alternative q = Ξ± ∘ mapα΅€ q

 extᴬ-agreement
  : funext 𝓀 𝓦₀
  β†’ {𝓧 : π•Š 𝓀} (f : ⟨ 𝓧 ⟩ β†’ ⟨ 𝓑 ⟩) (t : T 𝓧)
  β†’ extᴬ f t = extᴬ-alternative f t
 extᴬ-agreement {𝓀} fe {𝓧} f t =
  extᴬ f t                                     =⟨refl⟩
  aext 𝓐 f t                                   =⟨ I ⟩
  aext 𝓐 (Ξ» x β†’ aext 𝓐 id (Ξ·α΅€ (f x))) t        =⟨ II ⟩
  aext 𝓐 (Ξ» x β†’ x) (ext 𝕋 (Ξ» x β†’ Ξ· 𝕋 (f x)) t) =⟨refl⟩
  extᴬ-alternative f t                         ∎
   where
    I  = ap (Ξ» - β†’ aext 𝓐 - t) (dfunext fe (Ξ» x β†’ (aunit 𝓐 id (f x))⁻¹))
    II = aassoc 𝓐 id (Ξ·α΅€ ∘ f) t

 unitᴬ : {𝓧 : π•Š 𝓀}
         (f : ⟨ 𝓧 ⟩ β†’ ⟨ 𝓑 ⟩)
         (x : ⟨ 𝓧 ⟩)
       β†’ aext 𝓐 {𝓀} {𝓧} f (Ξ·α΅€ x) = f x
 unitᴬ = aunit 𝓐

\end{code}

Free algebras.

\begin{code}

module _ {𝓣₀ : Universe}
         {β„“ : Universe β†’ Universe}
         (𝕋 : Relative-Monad {β„“})
         (𝓐 : π•Š 𝓣₀)
       where

 open relative-T-definitions 𝕋

 free-relative-algebra : Relative-Algebra 𝕋 (T 𝓐)
 free-relative-algebra =
  record {
    aext   = extα΅€
  ; aunit  = unitα΅€
  ; aassoc = assocα΅€
  }

\end{code}

TODO. Define Relative-Monad morphism (for example overline is a
Relative-Monad morphism from J to K).