Even and Odd data types

Definition of the mutually recursive data types Even and Odd.

module even-odd where

open import map
open import phantomNat using (phantomZero[] ; phantomSuc[_] ; ⊢phantomZero ; ⊢phantomSuc)
open import Data.List using (_∷_ ; [] ; [_] )
open import Data.Vec renaming (_∷_ to _¦_ ; [] to [||] ; [_] to [|_|])
open import Data.Unit renaming (tt to ∗)
open import Data.Product using (_,_)
We define the variables and contexts used in the rest of the file.
α β : mix-var
α = tvar 0
β = tvar 1

Γα Γβ : context {mix-var}
Γα = ⟦ [| α |] ⟧
Γβ = ⟦ [| β |] ⟧

We define now the data types Even and Odd as they usually appear in the literature. Even has two constructors, one proving that phantomZero is even, and one producing a proof that phantomSuc n is even from a proof that n is odd. Odd has a unique constructor producing a proof that phantomSuc n is odd from a proof that n is even.

Even-id Odd-id : id-TC-var
Even-id = 8
Odd-id = 9

Even-name Odd-name : TC-var 1
Even-name = TC Even-id 1
Odd-name = TC Odd-id 1

even-zero-id even-suc-id odd-suc-id : id-data-constructor
even-zero-id = 80
even-suc-id = 81
odd-suc-id = 90

even-zero even-suc odd-suc : data-constructor 1
even-zero = even-zero-id ∷ [] ⇒ᵀ [| phantomZero[] |]
even-suc = even-suc-id ∷ [ appᵀ Odd-name [ [| varᵀ α |] ] ] ⇒ᵀ [| phantomSuc[ varᵀ α ] |]
odd-suc = odd-suc-id ∷ [ appᵀ Even-name [ [| varᵀ β |] ] ] ⇒ᵀ [| phantomSuc[ varᵀ β ] |]

Even Odd : user-defined 1
Even = dataᵀ Even-name whereᵀ (even-zero ∷ even-suc ∷ [])
Odd = dataᵀ Odd-name whereᵀ [ odd-suc ]

Even[_] = λ n → data-typeᵀ Even [ [| n |] ]
Odd[_] = λ n → data-typeᵀ Odd [ [| n |] ]
even-zero[] = dc even-zero [||]
even-suc[_] = λ x → dc even-suc [| x |]
odd-suc[_] = λ x → dc odd-suc [| x |]

Here are the justifications for Odd and Even. Notice the need for Odd-name in the TC context of the justification of even-suc, and, conversely, the need for Even-name in the TC context of the justification of odd-suc. This is where the mutual recursive definition manifests.

⊢even-zero : ∅ ∥ ∅ ⊢ᶜ even-zero
⊢even-zero = dcᵀ-intro {G = Even-name} ∗ (⊢phantomZero , ∗)

⊢even-suc : Γα ∥ (∅ , (_ , Odd-name)) ⊢ᶜ even-suc
⊢even-suc = dcᵀ-intro {G = Even-name} (app-intro (var-intro ∋-last , ∗) (∋-rec ∋-last) , ∗) (⊢phantomSuc (var-intro ∋-last , ∗) , ∗)

⊢odd-suc : Γβ ∥ (∅ , (_ , Even-name)) ⊢ᶜ odd-suc
⊢odd-suc = dcᵀ-intro {G = Odd-name} ((app-intro (var-intro ∋-last , ∗) (∋-rec ∋-last) , ∗)) (⊢phantomSuc (var-intro ∋-last , ∗)  , ∗)
 
⊢Even : ∀ {Γ χ φ} → _ → Γ ∥ χ ⊢ Even[ φ ]
⊢Even ⊢φ =
  data-intro {Γcs = ∅ ∷ Γα ∷ []} {χcs = ∅ ∷ (∅ , (_ , Odd-name)) ∷ []}
  (⊢even-zero , ⊢even-suc , ∗) (⊢φ , ∗)

⊢Odd : ∀ {Γ χ φ} → _ → Γ ∥ χ ⊢ Odd[ φ ]
⊢Odd ⊢φ =
  data-intro {Γcs = Γβ ∷ []} {χcs = (∅ , (_ , Even-name)) ∷ []}
  (⊢odd-suc , ∗) (⊢φ , ∗)

By comparison with calls to adm on terms of non-mutually-recursive data types, a call to adm on a term in Even or in Odd will need to carry a non-empty stack of already-encountered data types. Indeed, if the call is made with an empty stack on a term of the form even-suc p, the algorithm will fail to recognize Odd at the known data type when examining the type of p. For that reason, we define the following ready-to-use stack:

Even∷Odd∷[] =
  (
    arity _
    def Even
    ctx (∅ ∷ Γα ∷ []) ∥ (∅ ∷ (∅ , (_ , Odd-name)) ∷ [])
    der (⊢even-zero , ⊢even-suc , ∗)
  ) ∷ (
    arity _
    def Odd
    ctx (Γβ ∷ []) ∥ ((∅ , (_ , Even-name)) ∷ [])
    der (⊢odd-suc , ∗)
  ) ∷ []