open import Data.Unit
open import Data.Empty
open import Data.Product
open import Data.Sum
open import Data.List
open import Data.Nat
open import Data.Bool
open import Data.Fin
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality
data Konst : Set where
bool : Konst
nat : Konst
data Atom : Set where
K : Konst → Atom
I : Atom
Prod Sum : Set
Prod = List Atom
Sum = List Prod
⟦_〛ₖ : Konst → Set
⟦ bool 〛ₖ = Bool
⟦ nat 〛ₖ = ℕ
⟦_〛ₐ : Atom → (Set → Set)
⟦ K k 〛ₐ _ = ⟦ k 〛ₖ
⟦ I 〛ₐ X = X
⟦_〛ₚ : Prod → (Set → Set)
⟦ [] 〛ₚ X = ⊤
⟦ α ∷ p 〛ₚ X = ⟦ α 〛ₐ X × ⟦ p 〛ₚ X
⟦_〛ₛ : Sum → (Set → Set)
⟦ [] 〛ₛ X = ⊥
⟦ π ∷ s 〛ₛ X = ⟦ π 〛ₚ X ⊎ ⟦ s 〛ₛ X
data Fix (σ : Sum) : Set where
⟨_⟩ : ⟦ σ 〛ₛ (Fix σ) → Fix σ
Constr : Sum → Set
Constr σ = Fin (length σ)
typeOf : (σ : Sum) → Constr σ → Prod
typeOf [] ()
typeOf (π ∷ _) zero = π
typeOf (_ ∷ σ) (suc π) = typeOf σ π
inj : (σ : Sum) → (σ' : Sum) → (C : Constr σ) → ⟦ typeOf σ C 〛ₚ (Fix σ') → ⟦ σ 〛ₛ (Fix σ')
inj [] _ ()
inj (x ∷ σ) _ zero p = inj₁ p
inj (x ∷ σ) σ' (suc c) p = inj₂ (inj σ σ' c p)
listF : Sum
listF = [] ∷ (K nat ∷ I ∷ []) ∷ []
list = ⟦ listF 〛ₛ (Fix listF)
nil : list
nil = inj listF listF zero tt
cons : ℕ → list → list
cons h t = inj listF listF (suc zero) (h , ⟨ t ⟩ , tt)
natPairF = (K nat ∷ K nat ∷ []) ∷ []
natPair = ⟦ natPairF 〛ₛ (Fix natPairF)
mkpairℕ : ℕ → ℕ → natPair
mkpairℕ n₁ n₂ = inj natPairF natPairF zero (n₁ , n₁ , tt)
eqₖ : (κ : Konst) → ⟦ κ 〛ₖ → ⟦ κ 〛ₖ → Bool
eqₖ bool x y with x Data.Bool.≟ y
... | yes _ = true
... | no _ = false
eqₖ nat x y with x Data.Nat.≟ y
... | yes _ = true
... | no _ = false
eqₐ : (α : Atom) → (σ : Sum) → ⟦ α 〛ₐ (Fix σ) → ⟦ α 〛ₐ (Fix σ) → Bool
eqₚ : (π : Prod) → (σ : Sum) → ⟦ π 〛ₚ (Fix σ) → ⟦ π 〛ₚ (Fix σ) → Bool
eqₛ : (σ : Sum) → (σ' : Sum) → ⟦ σ 〛ₛ (Fix σ') → ⟦ σ 〛ₛ (Fix σ') → Bool
eqₐ (K k) σ x y = eqₖ k x y
eqₐ I σ ⟨ x ⟩ ⟨ y ⟩ = eqₛ σ σ x y
eqₚ [] σ x y = true
eqₚ (α ∷ π) σ (u , v) (w , x) = eqₐ α σ u w ∧ eqₚ π σ v x
eqₛ [] _ () ()
eqₛ (π ∷ _) σ' (inj₁ x) (inj₁ y) = eqₚ π σ' x y
eqₛ (_ ∷ _) _ (inj₁ x) (inj₂ y) = false
eqₛ (_ ∷ _) _ (inj₂ x) (inj₁ y) = false
eqₛ (π ∷ σ) σ' (inj₂ x) (inj₂ y) = eqₛ σ σ' x y
eqList : list → list → Bool
eqList = eqₛ listF listF
eqℕPair : natPair → natPair → Bool
eqℕPair = eqₛ natPairF natPairF
check₁ : eqList
(cons zero (cons (suc zero) nil))
(cons zero (cons (suc (suc zero)) nil)) ≡ false
check₁ = refl
check₂ : eqList
(cons zero (cons (suc (suc zero)) nil))
(cons zero (cons (suc (suc zero)) nil)) ≡ true
check₂ = refl
check₃ : eqℕPair (mkpairℕ (suc (suc zero)) zero)
(mkpairℕ (suc (suc zero)) zero)
≡ true
check₃ = refl
check₄ : eqℕPair (mkpairℕ (suc (suc zero)) zero)
(mkpairℕ (suc (suc (suc zero))) zero)
≡ false
check₄ = refl