Search code examples
functional-programmingagdabottom-type

Understanding Assignment Solution in Agda


Consider the following extracted piece of code for proving the "Unicity of Typing" for variable in Agda:

unicity : ∀ {Γ₁ Γ₂ e τ₁ τ₂} →  (Γ₁ ⊢ e ∷ τ₁) → (Γ₂ ⊢ e ∷ τ₂) → (Γ₁ ≈ Γ₂) → (τ₁ ∼ τ₂)
unicity   (VarT here) (VarT here) (_ , ( τ∼ , _ ))   = τ∼ 
unicity (VarT here) (VarT (ski`p {α = α} lk2)) (s≡s' , ( _ , _ )) = ⊥-elim (toWitnessFalse α (toWitness` s≡s'))
unicity (VarT (skip {α = α} lk1)) (VarT here) (s'≡s , ( _ , _ )) = ⊥-elim (toWitnessFalse α (toWitness s'≡s))
unicity (VarT (skip lk1)) (VarT (skip lk2)) (_ ,( _ , Γ≈ ))     = unicity (VarT lk1) (VarT lk2) Γ≈

I need an explanation on the working of ⊥-elim , toWitnessFalse and toWitness. Also, what do the expressions and mean/stand for?


Solution

  • is the empty type, so (in a total, consistent language) you can never construct a value of type . But this also means that any proposition you can think of, follows from . This is what ⊥-elim witnesses:

    ⊥-elim : ∀ {w} {Whatever : Set w} → ⊥ → Whatever
    

    This is very useful in practice because you might be writing proofs under some assumption, and some of those assumptions might be , or they might be negative statements (A → ⊥ for some A) and you can prove the A as well, etc. Then, what you find out is effectively that you don't have to care about that particular branch anymore, since it is impossible; but then, just because you don't care, you still have to formally satisfy the result type somehow. This is what ⊥-elim gives you.

    toWitness's type and related definitions are as follows:

    T : Bool → Set
    T true  = ⊤
    T false = ⊥
    
    ⌊_⌋ : ∀ {p} {P : Set p} → Dec P → Bool
    ⌊ yes _ ⌋ = true
    ⌊ no  _ ⌋ = false
    
    True : ∀ {p} {P : Set p} → Dec P → Set
    True Q = T ⌊ Q ⌋
    
    toWitness : ∀ {p} {P : Set p} {Q : Dec P} → True Q → P
    

    Given a Q : Dec P, True Q is either (if Q = yes _) or (if Q = no _). The only way to call toWitness, then, is to have Q say that P is true and pass the trivial unit constructor tt : ⊤; the only other possibility would be to have Q say that P is false, and pass as an argument a but as we've seen, that's not possible. In summary, toWitness says that if Q tells us the decision that P holds, then we can get a proof of P from Q.

    toWitnessFalse is exactly the same with the roles reversed: if Q tells us the decision that P doesn't hold, then we can get a proof of ¬ P from Q.