module mi.Prelude where

open import Agda.Builtin.Bool public
  using (Bool ; true ; false)

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

open import Agda.Builtin.FromNat public
  using (Number ; fromNat)

open import Agda.Builtin.Nat public
  using (Nat ; zero ; suc ; _+_ ; _-_ ; _*_)

open import Agda.Builtin.Sigma public
  using (Σ ; fst ; snd)
  renaming (_,_ to sig)

open import Agda.Builtin.Unit public
  using ( ; tt)

open import Agda.Primitive public
  using (Level ; _⊔_ ; Setω)
  renaming (lzero to 0ℓ ; lsuc to sucℓ)


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

-- tiny basics

data  : Set where

infix 3 ¬_
¬_ :  {𝓍} (X : Set 𝓍)  Set 𝓍
¬ X = X  

abort :  {𝓍} {X : Set 𝓍}    X
abort ()

_↯_ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎}  X  ¬ X  Y
x  ¬x = abort (¬x x)

infixr 1 _∨_
data _∨_ {𝓍 𝓎} (X : Set 𝓎) (Y : Set 𝓎) : Set (𝓍  𝓎) where
  left  :  (x : X)  X  Y
  right :  (y : Y)  X  Y

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

T : Bool  Set
T true  = 
T false = 

T? :  (b : Bool)  Dec (T b)
T? true  = yes tt
T? false = no  ())

module _ {𝓍} {X : Set 𝓍} where
  True : Dec X  Set
  True (yes _) = 
  True (no _)  = 

  toWitness : {X? : Dec X}  True X?  X
  toWitness {X?} p  with X?
  toWitness {X?} _  | yes x = x
  toWitness {X?} () | no _

  fromWitness : {X? : Dec X}  X  True X?
  fromWitness {X?} x with X?
  fromWitness {X?} _ | yes _ = tt
  fromWitness {X?} x | no ¬x = x  ¬x

  mapDec :  {𝓎} {Y : Set 𝓎}  (X  Y)  (Y  X)  Dec X  Dec Y
  mapDec f _ (yes x) = yes (f x)
  mapDec _ g (no ¬x) = no  y  g y  ¬x)

-- numeric literals for naturals
instance
  literalNat : Number Nat
  literalNat = record
      { Constraint = λ _  
      ; fromNat    = λ n {{_}}  n
      }

module Pointless where
  id :  {𝓍} {X : Set 𝓍}  X  X
  id x = x

  infixr 9 _∘_
  _∘_ :  {𝓍 𝓎 𝓏} {X : Set 𝓍} {Y : X  Set 𝓎} {Z :  {x}  Y x  Set 𝓏}
          (f :  {x} (y : Y x)  Z y) (g :  x  Y x)   x  Z (g x)
  (f  g) x = f (g 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


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

-- equality

≡-syntax :  {𝓍} (X : Set 𝓍)  X  X  Set 𝓍
≡-syntax X = _≡_

infix 4 ≡-syntax
syntax ≡-syntax X x x′ = x  x′ :> X

module  where
  infix 9 _⁻¹
  _⁻¹ :  {𝓍} {X : Set 𝓍} {x x′ : X}  x  x′  x′  x
  refl ⁻¹ = refl

  infixr 4 _⋮_
  _⋮_ :  {𝓍} {X : Set 𝓍} {x x′ x″ : X}  x  x′  x′  x″  x  x″
  refl  q = q

  infixl 9 _&_
  _&_ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎} (f : X  Y) {x x′}  x  x′  f x  f x′
  _ & 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 _ = refl

Funext : Setω
Funext =  {𝓍 𝓎} {X : Set 𝓍} {Y : X  Set 𝓎} 
           {f g :  x  Y x}  (∀ x  f x  g x)  f  g

congapp′ :  {𝓍 𝓎} {X : Set 𝓍} {Y : X  Set 𝓎} 
             {f g :  {x}  Y x}  f  g :> (∀ {x}  Y x)  (∀ {x}  f {x}  g {x})
congapp′ refl {_} = refl

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 funext p =  f {x}  f x) ≡.& funext  x  p {x})

module ≡-Reasoning where
  open  public

  infix  3 _∎
  infixr 2 _≡⟨⟩_ _≡⟨_⟩_
  infix  1 begin_

  begin_ :  {𝓍} {X : Set 𝓍} {x x′ : X}  x  x′  x  x′
  begin p = p

  _≡⟨⟩_ :  {𝓍} {X : Set 𝓍} (x : X) {x′ : X}  x  x′  x  x′
  _ ≡⟨⟩ p = p

  _≡⟨_⟩_ :  {𝓍} {X : Set 𝓍} (x : X) {x′ x″}  x  x′  x′  x″  x  x″
  _ ≡⟨ p  q = p  q

  _∎ :  {𝓍} {X : Set 𝓍} (x : X)  x  x
  _  = refl

uip :  {𝓍} {X : Set 𝓍} {x x′ : X} (p p′ : x  x′)  p  p′
uip refl refl = refl


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

-- heterogeneous equality
-- TODO: compare with stdlib

infix 4 _≅_
data _≅_ {𝓍} {X : Set 𝓍} (x : X) :  {𝓎} {Y : Set 𝓎}  Y  Set 𝓍 where
   refl : x  x

module  where
  infix 9 _⁻¹
  _⁻¹ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎} {x : X} {y : Y}  x  y  y  x
  refl ⁻¹ = refl

  infixr 4 _⋮_
  _⋮_ :  {𝓍 𝓎 𝓏} {X : Set 𝓍} {Y : Set 𝓎} {Z : Set 𝓏} {x : X} {y : Y} {z : Z} 
          x  y  y  z  x  z
  refl  q = q

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

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

≅→≡ :  {𝓍} {X : Set 𝓍} {x x′ : X}  x  x′  x  x′
≅→≡ refl = refl

≡→≅ :  {𝓍} {X : Set 𝓍} {x x′ : X}  x  x′  x  x′
≡→≅ refl = refl

module ≅-Reasoning where
  open  public

  infix  3 _∎
  infixr 2 _≅⟨⟩_ _≅⟨_⟩_ _≡⟨⟩_ _≡⟨_⟩_
  infix  1 begin_

  begin_ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎} {x : X} {y : Y}  x  y  x  y
  begin p = p

  _≅⟨⟩_ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎} (x : X) {y : Y}  x  y  x  y
  _ ≅⟨⟩ p = p

  _≅⟨_⟩_ :  {𝓍 𝓎 𝓏} {X : Set 𝓍} {Y : Set 𝓎} {Z : Set 𝓏} (x : X) {y : Y} {z : Z} 
             x  y  y  z  x  z
  _ ≅⟨ p  q = p  q

  _≡⟨⟩_ :  {𝓍} {X : Set 𝓍} (x : X) {x′}  x  x′  x  x′
  _ ≡⟨⟩ p = ≡→≅ p

  _≡⟨_⟩_ :  {𝓍 𝓏} {X : Set 𝓍} {Z : Set 𝓏} (x : X) {x′} {z : Z}  x  x′  x′  z  x  z
  _ ≡⟨ p  q = ≡→≅ p  q

  _∎ :  {𝓍} {X : Set 𝓍} (x : X)  x  x
  _  = refl


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

-- tiny naive category theory

module Gan (funext : Funext) where
  open  public

  record Category ( 𝓂 : Level) : Set (sucℓ (  𝓂)) where
    field
      Obj  : Set 
      _▻_  :  (x y : Obj)  Set 𝓂
      id   :  {x}  x  x
      _∘_  :  {x y z} (q : y  z) (p : x  y)  x  z
      lid▻ :  {x y} (p : y  x)  id  p  p
      rid▻ :  {x y} (p : y  x)  p  id  p
      ass▻ :  {w x y z} (r : y  z) (q : x  y) (p : w  x)  r  (q  p)  (r  q)  p

    _◅_ :  (y x : Obj)  Set 𝓂
    _◅_ = Pointless.flip _▻_

    _⨾_ :  {x y z} (p : x  y) (q : y  z)  x  z
    _⨾_ = Pointless.flip _∘_

    field
      ◅ssa :  {w x y z} (p : y  z) (q : x  y) (r : w  x)  p  (q  r)  (p  q)  r

  _ᵒᵖ :  { 𝓂} (C : Category  𝓂)  Category  𝓂
  _ᵒᵖ C = record
      { Obj  = C.Obj
      ; _▻_  = Pointless.flip C._▻_
      ; id   = C.id
      ; _∘_  = Pointless.flip C._∘_
      ; lid▻ = C.rid▻
      ; rid▻ = C.lid▻
      ; ass▻ = C.◅ssa
      ; ◅ssa = C.ass▻
      }
    where
      module C = Category C

  catSet :  (𝓍 : Level)  Category (sucℓ 𝓍) 𝓍
  catSet 𝓍 = record
      { Obj  = Set 𝓍
      ; _▻_  = λ X Y  X  Y
      ; id   = λ x  x
      ; _∘_  = λ q p x  q (p x)
      ; lid▻ = λ _  refl
      ; rid▻ = λ _  refl
      ; ass▻ = λ _ _ _  refl
      ; ◅ssa = λ _ _ _  refl
      }

  catSet₀ : Category (sucℓ 0ℓ) 0ℓ
  catSet₀ = catSet 0ℓ

  record Functor { ℴ′ 𝓂 𝓂′} (C : Category  𝓂) (D : Category ℴ′ 𝓂′) : Set (  ℴ′  𝓂  𝓂′) where
    private
      module C = Category C
      module D = Category D

    field
      ƒObj :  (x : C.Obj)  D.Obj
      ƒ    :  {x y} (p : x C.▻ y)  ƒObj x D.▻ ƒObj y
      idƒ  :  {x}  ƒ C.id  D.id :> (ƒObj x D.▻ ƒObj x)
      _∘ƒ_ :  {x y z} (q : y C.▻ z) (p : x C.▻ y)  ƒ (q C.∘ p)  ƒ q D.∘ ƒ p

    op : Functor (C ᵒᵖ) (D ᵒᵖ)
    op = record
        { ƒObj = ƒObj
        ; ƒ    = ƒ
        ; idƒ  = idƒ
        ; _∘ƒ_ = Pointless.flip _∘ƒ_
        }

  Presheaf :  { 𝓂} (C : Category  𝓂) (𝓍 : Level)  Set (  𝓂  sucℓ 𝓍)
  Presheaf C 𝓍 = Functor (C ᵒᵖ) (catSet 𝓍)


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

-- term variables, or untyped de Bruijn indices, or finite sets

data Fin : Nat  Set where
  zero :  {n}  Fin (suc n)
  suc  :  {n} (i : Fin n)  Fin (suc n)

-- numeric literals for term variables
module _ where
  data Fin⟨_>_⟩ : Nat  Nat  Set where
    instance
      zero :  {k}  Fin⟨ suc k > zero 
      suc  :  {k n} {{i : Fin⟨ k > n }}  Fin⟨ suc k > suc n 

  Fin◇→Fin :  {k} (n : Nat) {{i : Fin⟨ k > n }}  Fin k
  Fin◇→Fin _       {{zero}} = zero
  Fin◇→Fin (suc n) {{suc}}  = suc (Fin◇→Fin n)

  instance
    literalFin :  {k}  Number (Fin k)
    literalFin {k} = record
        { Constraint = Fin⟨ k >_⟩
        ; fromNat    = Fin◇→Fin
        }

-- order-preserving embeddings of term variables
infix 3 _≤_
data _≤_ : Nat  Nat  Set where
  stop  : zero  zero
  wk≤   :  {k k′} (η : k  k′)  k  suc k′
  lift≤ :  {k k′} (η : k  k′)  suc k  suc k′

id≤ :  {k}  k  k
id≤ {k = zero}  = stop
id≤ {k = suc k} = lift≤ id≤

infixr 9 _∘≤_
_∘≤_ :  {k k′ k″}  k′  k″  k  k′  k  k″
stop     ∘≤ η       = η
wk≤ η′   ∘≤ η       = wk≤ (η′ ∘≤ η)
lift≤ η′ ∘≤ wk≤ η   = wk≤ (η′ ∘≤ η)
lift≤ η′ ∘≤ lift≤ η = lift≤ (η′ ∘≤ η)

renFin :  {k k′}  k  k′  Fin k  Fin k′
renFin stop      i       = i
renFin (wk≤ η)   i       = suc (renFin η i)
renFin (lift≤ η) zero    = zero
renFin (lift≤ η) (suc i) = renFin (wk≤ η) i

module _ where
  open 

  lid≤ :  {k k′} (η : k  k′)  id≤ ∘≤ η  η
  lid≤ stop      = refl
  lid≤ (wk≤ η)   = wk≤ & lid≤ η
  lid≤ (lift≤ η) = lift≤ & lid≤ η

  rid≤ :  {k k′} (η : k  k′)  η ∘≤ id≤  η
  rid≤ stop      = refl
  rid≤ (wk≤ η)   = wk≤ & rid≤ η
  rid≤ (lift≤ η) = lift≤ & rid≤ η

  ass≤ :  {k k′ k″ k‴} (η″ : k″  k‴) (η′ : k′  k″) (η : k  k′) 
           η″ ∘≤ (η′ ∘≤ η)  (η″ ∘≤ η′) ∘≤ η
  ass≤ stop       η′         η         = refl
  ass≤ (wk≤ η″)   η′         η         = wk≤ & ass≤ η″ η′ η
  ass≤ (lift≤ η″) (wk≤ η′)   η         = wk≤ & ass≤ η″ η′ η
  ass≤ (lift≤ η″) (lift≤ η′) (wk≤ η)   = wk≤ & ass≤ η″ η′ η
  ass≤ (lift≤ η″) (lift≤ η′) (lift≤ η) = lift≤ & ass≤ η″ η′ η

  idrenFin :  {k} (i : Fin k)  renFin id≤ i  i
  idrenFin zero    = refl
  idrenFin (suc i) = suc & idrenFin i

  comprenFin :  {k k′ k″} (η′ : k′  k″) (η : k  k′) (i : Fin k) 
                 renFin (η′ ∘≤ η) i  renFin η′ (renFin η i)
  comprenFin stop       η         i       = refl
  comprenFin (wk≤ η′)   η         i       = suc & comprenFin η′ η i
  comprenFin (lift≤ η′) (wk≤ η)   i       = suc & comprenFin η′ η i
  comprenFin (lift≤ η′) (lift≤ η) zero    = refl
  comprenFin (lift≤ η′) (lift≤ η) (suc i) = suc & comprenFin η′ η i

-- category of order-preserving embeddings of term variables
module ≤-Gan (funext : Funext) where
  open Gan funext

  cat≤ : Category 0ℓ 0ℓ
  cat≤ = record
      { Obj  = Nat
      ; _▻_  = _≤_
      ; id   = id≤
      ; _∘_  = _∘≤_
      ; lid▻ = lid≤
      ; rid▻ = rid≤
      ; ass▻ = ass≤
      ; ◅ssa = λ η η′ η″  ass≤ η″ η′ η ⁻¹
      } ᵒᵖ

  pshrenFin : Presheaf cat≤ 0ℓ
  pshrenFin = record
      { ƒObj = λ k  Fin k
      ; ƒ    = renFin
      ; idƒ  = funext idrenFin
      ; _∘ƒ_ = λ η′ η  funext (comprenFin η′ η)
      }


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

-- leftist lists and vectors

infixl 4 _,_
data List {𝓍} (X : Set 𝓍) : Set 𝓍 where
     : List X
  _,_ :  (ξ : List X) (x : X)  List X

data Vec {𝓍} (X : Set 𝓍) : Nat  Set 𝓍 where
     : Vec X zero
  _,_ :  {n} (ξ : Vec X n) (x : X)  Vec X (suc n)

module _ {𝓍} {X : Set 𝓍} where
  peek :  {n}  Fin n  Vec X n  X
  peek zero    (ξ , x) = x
  peek (suc i) (ξ , x) = peek i ξ

  poke :  {n}  Fin n  X  Vec X n  Vec X n
  poke zero    w (ξ , x) = ξ , w
  poke (suc i) w (ξ , x) = poke i w ξ , x

  for :  {𝓎} {Y : Set 𝓎} {n}  Vec X n  (X  Y)  Vec Y n
  for        f = 
  for (ξ , x) f = for ξ f , f x

  tab :  {n}  (Fin n  X)  Vec X n
  tab {zero}  f = 
  tab {suc n} f = tab  i  f (suc i)) , f zero


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

-- derivation variables, or typed de Bruijn indices

module _ {𝓍} {X : Set 𝓍} where
  infix 3 _∋_
  data _∋_ : List X  X  Set 𝓍 where
    zero :  {Γ A}  Γ , A  A
    suc  :  {Γ A C} (i : Γ  A)  Γ , C  A

  -- numeric literals for derivation variables
  module _ where
    infix 3 _∋⟨_⟩_
    data _∋⟨_⟩_ : List X  Nat  X  Set 𝓍 where
      instance
        zero :  {Γ A}  Γ , A ∋⟨ zero  A
        suc  :  {Γ A C n} {{i : Γ ∋⟨ n  A}}  Γ , C ∋⟨ suc n  A

    ∋◇→∋ :  {Γ A} (n : Nat) {{i : Γ ∋⟨ n  A}}  Γ  A
    ∋◇→∋ _       {{zero}} = zero
    ∋◇→∋ (suc n) {{suc}}  = suc (∋◇→∋ n)

    instance
      number∋ :  {Γ A}  Number (Γ  A)
      number∋ {Γ} {A} = record
          { Constraint = Γ ∋⟨_⟩ A
          ; fromNat    = ∋◇→∋
          }

  -- order-preserving embeddings of derivation variables
  infix 3 _⊆_
  data _⊆_ : List X  List X  Set 𝓍 where
    stop  :   
    wk⊆   :  {Γ Γ′ C} (η : Γ  Γ′)  Γ  Γ′ , C
    lift⊆ :  {Γ Γ′ C} (η : Γ  Γ′)  Γ , C  Γ′ , C

  id⊆ :  {Γ}  Γ  Γ
  id⊆ {Γ = }     = stop
  id⊆ {Γ = Γ , A} = lift⊆ id⊆

  infixr 9 _∘⊆_
  _∘⊆_ :  {Γ Γ′ Γ″}  Γ′  Γ″  Γ  Γ′  Γ  Γ″
  stop     ∘⊆ η       = η
  wk⊆ η′   ∘⊆ η       = wk⊆ (η′ ∘⊆ η)
  lift⊆ η′ ∘⊆ wk⊆ η   = wk⊆ (η′ ∘⊆ η)
  lift⊆ η′ ∘⊆ lift⊆ η = lift⊆ (η′ ∘⊆ η)

  ren∋ :  {Γ Γ′ A}  Γ  Γ′  Γ  A  Γ′  A
  ren∋ stop      i       = i
  ren∋ (wk⊆ η)   i       = suc (ren∋ η i)
  ren∋ (lift⊆ η) zero    = zero
  ren∋ (lift⊆ η) (suc i) = suc (ren∋ η i)

  module _ where
    open 

    lid⊆ :  {Γ Γ′} (η : Γ  Γ′)  id⊆ ∘⊆ η  η
    lid⊆ stop      = refl
    lid⊆ (wk⊆ η)   = wk⊆ & lid⊆ η
    lid⊆ (lift⊆ η) = lift⊆ & lid⊆ η

    rid⊆ :  {Γ Γ′} (η : Γ  Γ′)  η ∘⊆ id⊆  η
    rid⊆ stop      = refl
    rid⊆ (wk⊆ η)   = wk⊆ & rid⊆ η
    rid⊆ (lift⊆ η) = lift⊆ & rid⊆ η

    ass⊆ :  {Γ Γ′ Γ″ Γ‴} (η″ : Γ″  Γ‴) (η′ : Γ′  Γ″) (η : Γ  Γ′) 
             η″ ∘⊆ (η′ ∘⊆ η)  (η″ ∘⊆ η′) ∘⊆ η
    ass⊆ stop       η′         η         = refl
    ass⊆ (wk⊆ η″)   η′         η         = wk⊆ & ass⊆ η″ η′ η
    ass⊆ (lift⊆ η″) (wk⊆ η′)   η         = wk⊆ & ass⊆ η″ η′ η
    ass⊆ (lift⊆ η″) (lift⊆ η′) (wk⊆ η)   = wk⊆ & ass⊆ η″ η′ η
    ass⊆ (lift⊆ η″) (lift⊆ η′) (lift⊆ η) = lift⊆ & ass⊆ η″ η′ η

    idren∋ :  {Γ A} (i : Γ  A)  ren∋ id⊆ i  i
    idren∋ zero    = refl
    idren∋ (suc i) = suc & idren∋ i

    compren∋ :  {Γ Γ′ Γ″ A} (η′ : Γ′  Γ″) (η : Γ  Γ′) (i : Γ  A) 
                 ren∋ (η′ ∘⊆ η) i  ren∋ η′ (ren∋ η i)
    compren∋ stop       η         i       = refl
    compren∋ (wk⊆ η′)   η         i       = suc & compren∋ η′ η i
    compren∋ (lift⊆ η′) (wk⊆ η)   i       = suc & compren∋ η′ η i
    compren∋ (lift⊆ η′) (lift⊆ η) zero    = refl
    compren∋ (lift⊆ η′) (lift⊆ η) (suc i) = suc & compren∋ η′ η i

-- category of order-preserving embeddings of derivation variables
module ⊆-Gan (funext : Funext) {𝓍} (X : Set 𝓍) where
  open Gan funext

  cat⊆ : Category 𝓍 𝓍
  cat⊆ = record
      { Obj  = List X
      ; _▻_  = _⊆_
      ; id   = id⊆
      ; _∘_  = _∘⊆_
      ; lid▻ = lid⊆
      ; rid▻ = rid⊆
      ; ass▻ = ass⊆
      ; ◅ssa = λ η η′ η″  ass⊆ η″ η′ η ⁻¹
      } ᵒᵖ

  pshren∋ : X  Presheaf cat⊆ 𝓍
  pshren∋ A = record
      { ƒObj = λ Γ  Γ  A
      ; ƒ    = ren∋
      ; idƒ  = funext idren∋
      ; _∘ƒ_ = λ η′ η  funext (compren∋ η′ η)
      }


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

-- continuation/double negation monad/applicative/functor
-- TODO: laws?
module _ where
  return :  {𝓍} {X : Set 𝓍}  X  ¬ ¬ X
  return x = λ k  k x

  infixl 1 _>>=_
  _>>=_ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎}  ¬ ¬ X  (X  ¬ ¬ Y)  ¬ ¬ Y
  mx >>= f =  k  mx  x  f x k))

  join :  {𝓍} {X : Set 𝓍}  ¬ ¬ ¬ ¬ X  ¬ ¬ X
  join mmx = mmx >>=  mx  mx)

  infixl 4 _⊛_
  _⊛_ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎}  ¬ ¬ (X  Y)  ¬ ¬ X  ¬ ¬ Y
  mf  mx = mf >>=  f  mx >>=  x  return (f x)))

  infixl 4 _<$>_
  _<$>_ :  {𝓍 𝓎} {X : Set 𝓍} {Y : Set 𝓎}  (X  Y)  ¬ ¬ X  ¬ ¬ Y
  f <$> mx = return f  mx

  -- TODO: bug?
  -- dnem : ∀ {𝓍} {X : Set 𝓍} → ¬ ¬ (X ∨ ¬ X)
  -- dnem = λ k → k (right (λ k′ → k (left k′)))


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