open import Level hiding (zero ; suc)

open import Chapter4.Desc
open import Chapter4.Desc.Tagged
open import Chapter4.Desc.Fixpoint

module Chapter7.NoConfusion 
         { : Level}
         (D : tagDesc ) 
       where

open import Level  hiding (zero) renaming (suc to sucL)
open import Function

open import Data.Empty
open import Data.Unit hiding (_≟_)
open import Data.Nat hiding (compare ; pred ; _≟_)
open import Data.Fin hiding (lift)
open import Data.Sum
open import Data.Product

open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality

Eq : (D : Desc ){X : Set }   D  X   D  X  Set 
Eq `1 (lift tt) (lift tt) = Lift 
Eq `var xs ys = xs  ys
Eq (D₁  D₂) (xs₁ , xs₂) (ys₁ , ys₂) = Eq D₁ xs₁ ys₁ × Eq D₂ xs₂ ys₂
Eq (D₁ `+ D₂) (inj₁ xs₁) (inj₁ ys₁) = Eq D₁ xs₁ ys₁
Eq (D₁ `+ D₂) (inj₁ xs₁) (inj₂ ys₂) = Lift 
Eq (D₁ `+ D₂) (inj₂ xs₁) (inj₁ ys₂) = Lift 
Eq (D₁ `+ D₂) (inj₂ xs₂) (inj₂ ys₂) = Eq D₂ xs₂ ys₂
Eq ( S T) (s₁ , xs) (s₂ , ys) = Σ[ q  s₁  s₂ ] Eq (T s₁) xs (subst  s   T s  _) (sym q) ys)
Eq ( S T) xs ys =  s  Eq (T s) (xs s) (ys s)


infix 4 _≟_

_≟_ : {n : }  Decidable {A = Fin n} _≡_
zero   zero   = yes refl
suc m  suc n  with m  n
suc m  suc .m | yes refl = yes refl
suc m  suc n  | no prf = no  q  prf (help q)) 
  where help : ∀{k}{m n : Fin k}  _≡_ {A = Fin ((suc k))} (suc m) (suc n)  m  n
        help refl = refl
zero   suc n  = no λ()
suc m  zero   = no λ()


NoConfusion : (x y : μ (toDesc D))  Set (sucL )
NoConfusion  lift x , args₁   lift y , args₂  with x  y
NoConfusion  lift .y , args₁   lift y , args₂ 
    | yes refl =  (P : Set )  (args₁  args₂  P)  P
NoConfusion  lift x , args₁   lift y , args₂ 
    | no q =  P  P

noConfusion : (x y :  toDesc D  (μ (toDesc D)))  x  y  NoConfusion ( x ) ( y )
noConfusion (lift x , args₁) (lift y , args₂) q with x  y
noConfusion (lift .y , .args₁) (lift y , args₁) refl | yes refl = λ P rec  rec refl
noConfusion (lift .y , .args₂) (lift y , args₂) refl | no notEq = ⊥-elim (notEq refl)