----------------------------------------------------------------------------------------------------

-- tiny standard library

module A202401.Prelude where

open import Agda.Builtin.Equality public
  using (_โ‰ก_ ; refl)

open import Agda.Builtin.Nat public
  using (zero ; suc)
  renaming (Nat to โ„•)

open import Agda.Builtin.Sigma public
  using (ฮฃ ; _,_ ; fst ; snd)

open import Agda.Builtin.Unit public
  using ()
  renaming (โŠค to ๐Ÿ™ ; tt to unit)

open import Agda.Primitive public
  using (Level ; _โŠ”_ ; lzero ; lsuc ; Setฯ‰)


----------------------------------------------------------------------------------------------------

-- function

id : โˆ€ {๐“} {X : Set ๐“} โ†’ X โ†’ X
id x = x

infixr -1 _$_
_$_ : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} โ†’ (โˆ€ x โ†’ Y x) โ†’ (โˆ€ x โ†’ Y x)
f $ x = f x

flip : โˆ€ {๐“ ๐“Ž ๐“} {X : Set ๐“} {Y : Set ๐“Ž} {Z : X โ†’ Y โ†’ Set ๐“} โ†’ (โˆ€ x y โ†’ Z x y) โ†’
       (โˆ€ y x โ†’ Z x y)
(flip f) y x = f x y

-- TODO: should _โˆ˜_ be infixl?
infixr 9 _โˆ˜_
_โˆ˜_ : โˆ€ {๐“ ๐“Ž ๐“} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} {Z : โˆ€ {x} โ†’ Y x โ†’ Set ๐“} โ†’
        (โˆ€ {x} (y : Y x) โ†’ Z y) โ†’ (g : โˆ€ x โ†’ Y x) โ†’
      (โˆ€ x โ†’ Z (g x))
(f โˆ˜ g) x = f (g x)

infixr 9 _โจพ_
_โจพ_ : โˆ€ {๐“ ๐“Ž ๐“} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} {Z : โˆ€ {x} โ†’ Y x โ†’ Set ๐“} (g : โˆ€ x โ†’ Y x) โ†’
        (โˆ€ {x} (y : Y x) โ†’ Z y) โ†’
      (โˆ€ x โ†’ Z (g x))
(g โจพ f) x = f (g x)


----------------------------------------------------------------------------------------------------

-- data

data Rist {๐“} (X : Set ๐“) : Set ๐“ where
  โˆ™   : Rist X
  _,_ : โˆ€ (ฮพ : Rist X) (x : X) โ†’ Rist X

infixr 2 _ร—_
_ร—_ : โˆ€ {๐“ ๐“Ž} (X : Set ๐“) (Y : Set ๐“Ž) โ†’ Set (๐“ โŠ” ๐“Ž)
X ร— Y = ฮฃ X ฮป _ โ†’ Y

infixr 1 _โŠŽ_
data _โŠŽ_ {๐“ ๐“Ž} (X : Set ๐“) (Y : Set ๐“Ž) : Set (๐“ โŠ” ๐“Ž) where
  left  : โˆ€ (x : X) โ†’ X โŠŽ Y
  right : โˆ€ (y : Y) โ†’ X โŠŽ Y

recโ„• : โˆ€ {๐“} {X : Set ๐“} โ†’ โ„• โ†’ X โ†’ (โ„• โ†’ X โ†’ X) โ†’ X
recโ„• zero    z s = z
recโ„• (suc n) z s = s n (recโ„• n z s)

record Irrelevant {๐“} (X : Set ๐“) : Set ๐“ where
  field .irrelevant : X

open Irrelevant public

private
  data Empty : Set where

๐Ÿ˜ : Set
๐Ÿ˜ = Irrelevant Empty

{-# DISPLAY Irrelevant Empty = ๐Ÿ˜ #-}

abort : โˆ€ {๐“} {X : Set ๐“} โ†’ ๐Ÿ˜ โ†’ X
abort ()

infix 3 ยฌ_
ยฌ_ : โˆ€ {๐“} โ†’ Set ๐“ โ†’ Set ๐“
ยฌ X = X โ†’ ๐Ÿ˜

_โ†ฏ_ : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : Set ๐“Ž} โ†’ X โ†’ ยฌ X โ†’ Y
x โ†ฏ ยฌx = abort (ยฌx x)

data Dec {๐“} (X : Set ๐“) : Set ๐“ where
  yes : โˆ€ (x : X) โ†’ Dec X
  no  : โˆ€ (ยฌx : ยฌ X) โ†’ Dec X


----------------------------------------------------------------------------------------------------

-- propositional equality

โ‰ก-syntax : โˆ€ {๐“} (X : Set ๐“) โ†’ X โ†’ X โ†’ Set ๐“
โ‰ก-syntax X = _โ‰ก_

infix 4 โ‰ก-syntax
syntax โ‰ก-syntax X x xโ€ฒ = x โ‰ก xโ€ฒ :> X

infix 9 _โปยน
sym _โปยน : โˆ€ {๐“} {X : Set ๐“} {x xโ€ฒ : X} โ†’ x โ‰ก xโ€ฒ โ†’ xโ€ฒ โ‰ก x
sym refl = refl
_โปยน = sym

infixr 4 _โ‹ฎ_
trans _โ‹ฎ_ : โˆ€ {๐“} {X : Set ๐“} {x xโ€ฒ xโ€ณ : X} โ†’ x โ‰ก xโ€ฒ โ†’ xโ€ฒ โ‰ก xโ€ณ โ†’ x โ‰ก xโ€ณ
trans refl eq = eq
_โ‹ฎ_ = trans

subst : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} (Y : X โ†’ Set ๐“Ž) {x xโ€ฒ} โ†’ x โ‰ก xโ€ฒ โ†’ Y x โ†’ Y xโ€ฒ
subst Y refl y = y

transport : โˆ€ {๐“} {X Y : Set ๐“} โ†’ X โ‰ก Y โ†’ X โ†’ Y
transport = subst id

infixl 9 _&_
cong _&_ : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : Set ๐“Ž} (f : X โ†’ Y) {x xโ€ฒ} โ†’ x โ‰ก xโ€ฒ โ†’ f x โ‰ก f xโ€ฒ
cong f refl = refl
_&_ = cong

congโ‚‚ : โˆ€ {๐“ ๐“Ž ๐“} {X : Set ๐“} {Y : Set ๐“Ž} {Z : Set ๐“} (f : X โ†’ Y โ†’ Z) {x xโ€ฒ y yโ€ฒ} โ†’ x โ‰ก xโ€ฒ โ†’
          y โ‰ก yโ€ฒ โ†’
        f x y โ‰ก f xโ€ฒ yโ€ฒ
congโ‚‚ f refl refl = refl

infixl 8 _โŠ—_
_โŠ—_ : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : Set ๐“Ž} {f g : X โ†’ Y} {x xโ€ฒ} โ†’ f โ‰ก g โ†’ x โ‰ก xโ€ฒ โ†’ f x โ‰ก g xโ€ฒ
refl โŠ— refl = refl

congapp : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} {f g : โˆ€ x โ†’ Y x} โ†’ f โ‰ก g โ†’ (โˆ€ x โ†’ f x โ‰ก g x)
congapp refl x = refl

congappโ€ฒ : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} {f g : โˆ€ {x} โ†’ Y x} โ†’ f โ‰ก g :> (โˆ€ {x} โ†’ Y x) โ†’
           (โˆ€ {x} โ†’ f {x} โ‰ก g {x})
congappโ€ฒ refl {x} = refl

FunExt : Setฯ‰
FunExt = โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} {f g : โˆ€ x โ†’ Y x} โ†’ (โˆ€ x โ†’ f x โ‰ก g x) โ†’ f โ‰ก g

FunExtโ€ฒ : Setฯ‰
FunExtโ€ฒ = โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} {f g : โˆ€ {x} โ†’ Y x} โ†’ (โˆ€ {x} โ†’ f {x} โ‰ก g {x}) โ†’
          f โ‰ก g :> (โˆ€ {x} โ†’ Y x)

implify : FunExt โ†’ FunExtโ€ฒ
implify โš  eq = (ฮป f {x} โ†’ f x) & โš  (ฮป x โ†’ eq {x})

uniโ‰ก : โˆ€ {๐“} {X : Set ๐“} {x xโ€ฒ : X} (eq eqโ€ฒ : x โ‰ก xโ€ฒ) โ†’ eq โ‰ก eqโ€ฒ
uniโ‰ก refl refl = refl

uni๐Ÿ˜ : โˆ€ (z zโ€ฒ : ๐Ÿ˜) โ†’ z โ‰ก zโ€ฒ
uni๐Ÿ˜ () ()

uniยฌ : โˆ€ {๐“} {X : Set ๐“} (f g : ยฌ X) โ†’ f โ‰ก g
uniยฌ f g = refl

module _ (โš  : FunExt) where
  uniโ†’ : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : Set ๐“Ž} (uniY : โˆ€ y yโ€ฒ โ†’ y โ‰ก yโ€ฒ) (f g : X โ†’ Y) โ†’ f โ‰ก g
  uniโ†’ uniY f g = โš  ฮป x โ†’ uniY (f x) (g x)

module โ‰ก-Reasoning {๐“} {X : Set ๐“} where
  infix 1 begin_
  begin_ : โˆ€ {x xโ€ฒ : X} โ†’ x โ‰ก xโ€ฒ โ†’ x โ‰ก xโ€ฒ
  begin_ eq = eq

  infixr 2 _โ‰กโŸจโŸฉ_
  _โ‰กโŸจโŸฉ_ : โˆ€ (x {xโ€ฒ} : X) โ†’ x โ‰ก xโ€ฒ โ†’ x โ‰ก xโ€ฒ
  x โ‰กโŸจโŸฉ eq = eq

  infixr 2 _โ‰กโŸจ_โŸฉ_
  _โ‰กโŸจ_โŸฉ_ : โˆ€ (x {xโ€ฒ xโ€ณ} : X) โ†’ x โ‰ก xโ€ฒ โ†’ xโ€ฒ โ‰ก xโ€ณ โ†’ x โ‰ก xโ€ณ
  x โ‰กโŸจ eq โŸฉ eqโ€ฒ = trans eq eqโ€ฒ

  infixr 2 _โ‰กห˜โŸจ_โŸฉ_
  _โ‰กห˜โŸจ_โŸฉ_ : โˆ€ (x {xโ€ฒ xโ€ณ} : X) โ†’ xโ€ฒ โ‰ก x โ†’ xโ€ฒ โ‰ก xโ€ณ โ†’ x โ‰ก xโ€ณ
  x โ‰กห˜โŸจ eq โŸฉ eqโ€ฒ = trans (sym eq) eqโ€ฒ

  infix  3 _โˆŽ
  _โˆŽ : โˆ€ (x : X) โ†’ x โ‰ก x
  _โˆŽ _ = refl


----------------------------------------------------------------------------------------------------

-- heterogeneous equality

infix 4 _โ‰…_
data _โ‰…_ {๐“} {X : Set ๐“} (x : X) : โˆ€ {๐“Ž} {Y : Set ๐“Ž} โ†’ Y โ†’ Set ๐“ where
   refl : x โ‰… x

โ‰…โ†’โ‰ก : โˆ€ {๐“} {X : Set ๐“} {x xโ€ฒ : X} โ†’ x โ‰… xโ€ฒ โ†’ x โ‰ก xโ€ฒ
โ‰…โ†’โ‰ก refl = refl

โ‰กโ†’โ‰… : โˆ€ {๐“} {X : Set ๐“} {x xโ€ฒ : X} โ†’ x โ‰ก xโ€ฒ โ†’ x โ‰… xโ€ฒ
โ‰กโ†’โ‰… refl = refl

hcong : โˆ€ {๐“ ๐“Ž} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} (f : โˆ€ x โ†’ Y x) {x xโ€ฒ} โ†’ x โ‰… xโ€ฒ โ†’ f x โ‰… f xโ€ฒ
hcong f refl = refl

hcongโ‚‚ : โˆ€ {๐“ ๐“Ž ๐“} {X : Set ๐“} {Y : X โ†’ Set ๐“Ž} {Z : โˆ€ x โ†’ Y x โ†’ Set ๐“}
           (f : โˆ€ x โ†’ (y : Y x) โ†’ Z x y) {x xโ€ฒ y yโ€ฒ} โ†’ x โ‰… xโ€ฒ โ†’ y โ‰… yโ€ฒ โ†’
         f x y โ‰… f xโ€ฒ yโ€ฒ
hcongโ‚‚ f refl refl = refl


----------------------------------------------------------------------------------------------------