{-# OPTIONS --without-K #-}
module Model.Exponential where

open import Cats.Category

open import Model.RGraph as RG using (RGraph)
open import Model.Type.Core
open import Model.Product
open import Util.HoTT.HLevel
open import Util.Prelude hiding (_×_ ; id ; _∘_)

open RGraph
open RG._⇒_


private
  variable Δ : RGraph


infixr 9 _↝_


Ap : ⟦Type⟧ Δ  Δ .Obj  RGraph
Ap {Δ} T δ = record
  { ObjHSet = T .ObjHSet δ
  ; eqHProp = eqHProp T (Δ .eq-refl _)
  ; eq-refl = λ x  T .eq-refl x
  }


_↝_ : (T U : ⟦Type⟧ Δ)  ⟦Type⟧ Δ
_↝_ T U = record
  { ObjHSet = λ γ  HLevel⁺ (Ap T γ RG.⇒ Ap U γ) (RG.⇒-IsSet {Ap T γ} {Ap U γ})
  ; eqHProp = λ γ≈γ′ f g
       ∀∙-HProp λ x
       ∀∙-HProp λ y
       T .eqHProp γ≈γ′ x y →-HProp′ U .eqHProp γ≈γ′ (f .RG.fobj x) (g .RG.fobj y)
  ; eq-refl = λ f  f .RG.feq
  }


curry : (T U V : ⟦Type⟧ Δ)
   T × U  V  T  U  V
curry {Δ} T U V f = record
  { fobj = λ {δ} t  record
    { fobj = λ u  f .fobj (t , u)
    ; feq = λ x≈y  f .feq (Δ .eq-refl δ) (T .eq-refl t , x≈y)
    }
  ; feq = λ γ≈γ′ x≈y v≈w  f .feq γ≈γ′ (x≈y , v≈w)
  }


eval : (T U : ⟦Type⟧ Δ)
   (T  U) × T  U
eval T U = record
  { fobj = λ { (f , x)  f .RG.fobj x }
  ; feq = λ { γ≈γ′ (f≈g , x≈y)  f≈g x≈y }
  }


eval∘curry : (T U V : ⟦Type⟧ Δ) {f : T × U  V}
   eval U V  ⟨_×_⟩ {B = U} (curry T U V f) id  f
eval∘curry T U V = ≈⁺ λ γ x  refl


instance
  hasExponentials :  {Δ}  HasExponentials (⟦Types⟧ Δ)
  hasExponentials .HasExponentials.hasBinaryProducts = hasBinaryProducts
  hasExponentials .HasExponentials._↝′_ T U = record
    { Cᴮ = T  U
    ; eval = eval T U
    ; curry′ = λ {A} f  record
      { arr = curry A T U f
      ; prop = eval∘curry A T U
      ; unique = λ {g} g-prop  ≈⁺ λ γ h  RG.≈→≡ (RG.≈⁺ λ x
           sym (g-prop .≈⁻ γ (h , x)))
      }
    }


module ⟦Types⟧↝ {Δ} = HasExponentials (hasExponentials {Δ})


↝-resp-≈⟦Type⟧ :  {Δ} (T T′ U U′ : ⟦Type⟧ Δ)
   T ≈⟦Type⟧ T′
   U ≈⟦Type⟧ U′
   T  U ≈⟦Type⟧ T′  U′
↝-resp-≈⟦Type⟧ {Δ} T T′ U U′ T≈T′ U≈U′
  = ⟦Types⟧↝.↝-resp-≅ {Δ} {T} {T′} {U} {U′} T≈T′ U≈U′


subT-↝ :  {Γ Δ} (f : Γ RG.⇒ Δ)
   (T U : ⟦Type⟧ Δ)
   subT f T  subT f U ≈⟦Type⟧ subT f (T  U)
subT-↝ {Γ} {Δ} f T U = record
  { forth = record
    { fobj = λ g  record
      { fobj = g .fobj
      ; feq = λ {x y} x≈y  transportEq U (g .feq (transportEq T x≈y))
      }
    ; feq = λ γ≈γ′ f≈g x≈y  f≈g x≈y
    }
  ; back = record
    { fobj = λ g  record
      { fobj = g .fobj
      ; feq = λ {x y} x≈y  transportEq U (g .feq (transportEq T x≈y))
      }
    ; feq = λ γ≈γ′ f≈g x≈y  f≈g x≈y
    }
  ; back-forth = ≈⁺ λ γ x  RG.≈→≡ (RG.≈⁺ λ y  refl)
  ; forth-back = ≈⁺ λ γ x  RG.≈→≡ (RG.≈⁺ λ y  refl)
  }