module Prelude.Identity where

open import Prelude.Level

----------------------------------------------------------------------
-- Homogeneous identity types
----------------------------------------------------------------------
infix 4 _≡_
data _≡_ {l : Level}{A : Set l}(x : A) : A  Set l where
  instance refl : x  x

{-# BUILTIN EQUALITY _≡_ #-}

----------------------------------------------------------------------
-- ≡ is an equivalence relation
----------------------------------------------------------------------
symm :
  {l : Level}
  {A : Set l}
  {x y : A}
  (_ : x  y)
   ---------
  y  x
symm refl = refl

trans :
  {l : Level}
  {A : Set l}
  {x y z : A}
  (_ : x  y)
  (_ : y  z)
   ---------
  x  z
trans p refl = p

----------------------------------------------------------------------
-- Transport
----------------------------------------------------------------------
cong :
  {l m : Level}
  {A : Set l}
  {B : Set m}
  (f : A  B)
  {x x' : A}
  (_ : x  x')
   ----------
  f x  f x'
cong _ refl = refl

cong₂ :
  {l m n : Level}
  {A : Set l}
  {B : Set m}
  {C : Set n}
  (f : A  B  C)
  {x x' : A}
  {y y' : B}
  (_ : x  x')
  (_ : y  y')
   -------------
  f x y  f x' y'
cong₂ _ refl refl = refl

cong₃ :
  {l m n o : Level}
  {A : Set l}
  {B : Set m}
  {C : Set n}
  {D : Set o}
  (f : A  B  C  D)
  {x x' : A}
  {y y' : B}
  {z z' : C}
  (_ : x  x')
  (_ : y  y')
  (_ : z  z')
   ------------------
  f x y z  f x' y' z'
cong₃ _ refl refl refl = refl

cong₄ :
  {l m n o p : Level}
  {A : Set l}
  {B : Set m}
  {C : Set n}
  {D : Set o}
  {E : Set p}
  (f : A  B  C  D  E)
  {x x' : A}
  {y y' : B}
  {z z' : C}
  {w w' : D}
  (_ : x  x')
  (_ : y  y')
  (_ : z  z')
  (_ : w  w')
   -----------------------
  f x y z w  f x' y' z' w'
cong₄ _ refl refl refl refl = refl

----------------------------------------------------------------------
-- Congruence
----------------------------------------------------------------------
subst :
  {l m : Level}
  {A : Set l}
  (B : A  Set m)
  {x x' : A}
  (_ : x  x')
   -------------
  B x  B x'
subst _ refl b = b

subst₂ :
  {l m : Level}
  {A B : Set l}
  (C : A  B  Set m)
  {x x' : A}
  {y y' : B}
  (_ : x  x')
  (_ : y  y')
   -----------------
  C x y  C x' y'
subst₂ _ refl refl c = c

subst₃ :
  {l m : Level}
  {A B C : Set l}
  (D : A  B  C  Set m)
  {x x' : A}
  {y y' : B}
  {z z' : C}
  (_ : x  x')
  (_ : y  y')
  (_ : z  z')
   --------------------
  D x y z  D x' y' z'
subst₃ _ refl refl refl d = d

subst₄ :
  {l m : Level}
  {A B C D : Set l}
  (E : A  B  C  D  Set m)
  {x x' : A}
  {y y' : B}
  {z z' : C}
  {w w' : D}
  (_ : x  x')
  (_ : y  y')
  (_ : z  z')
  (_ : w  w')
   -----------------------
  E x y z w  E x' y' z' w'
subst₄ _ refl refl refl refl d = d

tpt :
  {l m n : Level}
  {A : Set l}
  (B : A  Set m)
  (C : (x : A)  B x  Set n)
  {x x' : A}
  {y : B x}
  {y' : B x'}
  (e : x  x')
  (_ : subst B e y  y')
   -------------------------
  C x y  C x' y'
tpt _ _ refl refl c = c

≡elim :
  {l m : Level}
  {A : Set l}
  {x x' : A}
  (B : (y : A)  x  y  Set m)
  (_ : B x refl)
  (e : x  x')
   ---------------------------
  B x' e

≡elim _ b refl = b

substInj :
  {l m : Level}
  {A : Set l}
  (B : A  Set m)
  {x x' : A}
  {y y' : B x}
  (e : x  x')
  (_ : subst B e y  subst B e y')
   ------------------------------
  y  y'
substInj _ refl e = e

substInv :
  {l m : Level}
  {A : Set l}
  (B : A  Set m)
  {x x' : A}
  {y : B x}
  {y' : B x'}
  (e : x  x')
  (_ : y'  subst B e y)
   ---------------------
  subst B (symm e) y'  y

substInv B refl refl = refl

-- subst-nat :
--  {l m : Level}
--  {A A' : Set l}
--  {x x' : A}
--  (B : A → Set m)
--  (B' : A' → Set m)
--  (f : A → A')
--  (g : ∀{x} → B x → B' (f x))
--  (e : x ≡ x')
--  (e' : f x ≡ f x')
--  (y : B x)
--  → --------------------------------
--  subst B' e' (g y) ≡ g (subst B e y)

-- subst-nat _ _ _ _ refl e _ = {!!}

----------------------------------------------------------------------
-- Chain reasoning
----------------------------------------------------------------------

{- Lifted from
  <agda-stdlib/src/Relation/Binary/Reasoning/Base/Single.agda> -}

module _ {l : Level}{A : Set l} where
  infix  4 _IsRelatedTo_
  data _IsRelatedTo_ (x y : A) : Set l where
    relTo : (x≡y : x  y)  x IsRelatedTo y

  -- Beginning of a proof
  infix  1 begin_
  begin_ :  {x y}  x IsRelatedTo y  x  y
  begin relTo x≡y = x≡y

  -- Step with a non-trivial propositional equality
  infixr 2 step-≡
  step-≡ :  x {y z}  y IsRelatedTo z  x  y  x IsRelatedTo z
  step-≡ _ x≡z refl = x≡z
  syntax step-≡  x y≡z x≡y = x ≡⟨  x≡y  y≡z

  -- Step with a flipped non-trivial propositional equality
  infixr 2 step-≡˘
  step-≡˘ :  x {y z}  y IsRelatedTo z  y  x  x IsRelatedTo z
  step-≡˘ _ x≡z refl = x≡z
  syntax step-≡˘ x y≡z y≡x = x ≡˘⟨ y≡x  y≡z

  -- Step with a trivial propositional equality
  infixr 2 _≡⟨⟩_
  _≡⟨⟩_ :  x {y}  x IsRelatedTo y  x IsRelatedTo y
  _ ≡⟨⟩ x≡y = x≡y

  -- Note that the arguments to the `step`s are not provided in their
  -- "natural" order and syntax declarations are later used to re-order
  -- them. This is because the `step` ordering allows the type-checker to
  -- better infer the middle argument `y` from the `_IsRelatedTo_`
  -- argument (see issue 622).
  --
  -- This has two practical benefits. First it speeds up type-checking by
  -- approximately a factor of 5. Secondly it allows the combinators to be
  -- used with macros that use reflection

  -- Termination
  infix  3 _∎
  _∎ :  x  x IsRelatedTo x
  x  = relTo refl