{-# OPTIONS --rewriting #-}

module A201801.Prelude where

open import Agda.Primitive public
  using (Level ; lzero ; lsuc ; _⊔_)

open import Agda.Builtin.Equality public
  using (_≡_ ; refl)

open import Agda.Builtin.Equality.Rewrite public
  using ()

open import Agda.Builtin.FromString public
  using (IsString ; fromString)

open import Agda.Builtin.Nat public
  using (Nat ; zero ; suc)

open import Agda.Builtin.String public
  using (String ; primStringEquality)

open import Agda.Builtin.Unit public
  using ()
  renaming (tt to )


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


Π :  { ℓ′}  Set   Set ℓ′  Set (  ℓ′)
Π X Y = X  Y


_∘′_ :  { ℓ′ ℓ″}  {X : Set } {P : X  Set ℓ′} {Q :  {x}  P x  Set ℓ″}
                    (f :  {x}  (y : P x)  Q y) (g :  x  P x) (x : X)
                    Q (g x)
(f ∘′ g) x = f (g x)


flip :  { ℓ′ ℓ″}  {X : Set } {Y : Set ℓ′} {Z : Set ℓ″}
                    (X  Y  Z)  Y  X
                    Z
flip f y x = f x y


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


data  : Set
  where


elim⊥ :  {}  {X : Set }    X
elim⊥ ()


¬_ :  {}  Set   Set 
¬ X = X  


_↯_ :  { ℓ′}  {X : Set } {Y : Set ℓ′}  X  ¬ X  Y
x  f = elim⊥ (f x)


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


infix 4 _≢_
_≢_ :  {}  {X : Set }  X  X  Set 
x  x′ = ¬ (x  x′)


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


record PER {} (X : Set ) (_≈_ : X  X  Set ) : Set 
  where
    infix 9 _⁻¹
    infixr 4 _⋮_
    field
      _⁻¹ :  {x y}  x  y  y  x
      _⋮_ :  {x y z}  x  y  y  z  x  z

open PER {{...}} public


instance
  per≡ :  {} {X : Set }  PER X _≡_
  per≡ = record
           { _⁻¹ = \ { refl  refl }
           ; _⋮_ = \ { refl refl  refl }
           }


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


infixl 9 _&_
_&_ :  { ℓ′}  {X : Set } {Y : Set ℓ′} {x y : X}
                (f : X  Y)  x  y
                f x  f y
f & refl = refl


infixl 8 _⊗_
_⊗_ :  { ℓ′}  {X : Set } {Y : Set ℓ′} {f g : X  Y} {x y : X}
                f  g  x  y
                f x  g y
refl  refl = refl


coerce :  {}  {X Y : Set }
                X  X  Y
                Y
coerce x refl = x


subst :  { ℓ′}  {X : Set } {x y : X}
                  (P : X  Set ℓ′)  x  y  P x
                  P y
subst P refl p = p


case_of_ :  { ℓ′}  {X : Set } {Y : Set ℓ′}
                     X  (X  Y)  Y
case x of f = f x


postulate
  funext! :  { ℓ′}  {X : Set } {P : X  Set ℓ′} {f g :  x  P x}
                      (∀ x  f x  g x)
                      f  g

postulate
  funext!′ :  { ℓ′}  {X : Set } {P : X  Set ℓ′} {f g :  {x}  P x}
                       (∀ x  f {x}  g {x})
                       (\ {x}  f {x})  (\ {x}  g {x})


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


module ≡-Reasoning {} {X : Set }
  where
    infix 1 begin_
    begin_ :  {x y : X}  x  y  x  y
    begin p = p

    infixr 2 _≡⟨⟩_
    _≡⟨⟩_ :  (x {y} : X)  x  y  x  y
    x ≡⟨⟩ p = p

    infixr 2 _≡⟨_⟩_
    _≡⟨_⟩_ :  (x {y z} : X)  x  y  y  z  x  z
    x ≡⟨ p  q = p  q

    infix 3 _∎
    _∎ :  (x : X)  x  x
    x  = refl


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


module Inspect
  where
    record Reveal_$_is_ { ℓ′} {X : Set } {P : X  Set ℓ′}
                               (f :  x  P x) (x : X) (y : P x)
                             : Set (  ℓ′)
      where
        constructor [_]
        field
          eq : f x  y


    inspect :  { ℓ′}  {X : Set } {P : X  Set ℓ′}
                        (f :  x  P x) (x : X)
                        Reveal f $ x is f x
    inspect f x = [ refl ]


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


data Dec {} (X : Set ) : Set 
  where
    yes : X  Dec X
    no  : ¬ X  Dec X


forD :  { ℓ′}  {X : Set } {Y : Set ℓ′}
                 Dec X  (X  Y)  (Y  X)
                 Dec Y
forD (yes x) f g = yes (f x)
forD (no ¬x) f g = no (\ y  g y  ¬x)


mapD :  { ℓ′}  {X : Set } {Y : Set ℓ′}
                 (X  Y)  (Y  X)  Dec X
                 Dec Y
mapD f g x = forD x f g


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


infixr 6 _,_
record Σ { ℓ′} (X : Set ) (P : X  Set ℓ′) : Set (  ℓ′)
  where
    constructor _,_
    field
      proj₁ : X
      proj₂ : P proj₁

open Σ public


infixr 2 _×_
_×_ :  { ℓ′}  Set   Set ℓ′  Set (  ℓ′)
X × Y = Σ X (\ x  Y)


forΣ :  { ℓ′ ℓ″ ℓ‴}  {X : Set } {Y : Set ℓ′} {P : X  Set ℓ″} {Q : Y  Set ℓ‴}
                       Σ X P  (f : X  Y) (g :  {x}  P x  Q (f x))
                       Σ Y Q
forΣ (x , y) f g = f x , g y


mapΣ :  { ℓ′ ℓ″ ℓ‴}  {X : Set } {Y : Set ℓ′} {P : X  Set ℓ″} {Q : Y  Set ℓ‴}
                       (f : X  Y) (g :  {x}  P x  Q (f x))  Σ X P
                       Σ Y Q
mapΣ f g p = forΣ p f g


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


infixl 1 _⊎_
data _⊎_ { ℓ′} (X : Set ) (Y : Set ℓ′) : Set (  ℓ′)
  where
    inj₁ : (x : X)  X  Y
    inj₂ : (y : Y)  X  Y


elim⊎ :  { ℓ′ ℓ″}  {X : Set } {Y : Set ℓ′} {Z : Set ℓ″}
                     X  Y  (X  Z)  (Y  Z)
                     Z
elim⊎ (inj₁ x) f g = f x
elim⊎ (inj₂ y) f g = g y


for⊎ :  { ℓ′ ℓ″ ℓ‴}  {X : Set } {Y : Set ℓ′} {U : Set ℓ″} {V : Set ℓ‴}
                       X  Y  (X  U)  (Y  V)
                       U  V
for⊎ s f g = elim⊎ s (\ x  inj₁ (f x)) (\ y  inj₂ (g y))


map⊎ :  { ℓ′ ℓ″ ℓ‴}  {X : Set } {Y : Set ℓ′} {U : Set ℓ″} {V : Set ℓ‴}
                       (X  U)  (Y  V)  X  Y
                       U  V
map⊎ f g s = for⊎ s f g


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


module _
  where
    open import Agda.Builtin.Bool
    open import Agda.Builtin.TrustMe

    _≟ₛ_ : (s₁ s₂ : String)  Dec (s₁  s₂)
    s₁ ≟ₛ s₂ with primStringEquality s₁ s₂
    ...    | true  = yes primTrustMe
    ...    | false = no s₁≢s₂
      where
        postulate
          s₁≢s₂ : s₁  s₂


instance
  stringIsString : IsString String
  stringIsString =
    record
      { Constraint = \ s  
      ; fromString = \ s  s
      }


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


inj-suc :  {n m}  suc n  suc m
                   n  m
inj-suc refl = refl


_≟ₙ_ : (n₁ n₂ : Nat)  Dec (n₁  n₂)
zero   ≟ₙ zero   = yes refl
zero   ≟ₙ suc n₂ = no (\ ())
suc n₁ ≟ₙ zero   = no (\ ())
suc n₁ ≟ₙ suc n₂ with n₁ ≟ₙ n₂
...              | yes refl = yes refl
...              | no n₁≢n₂ = no (n₁≢n₂ ∘′ inj-suc)


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