-- Normalization for Intuitionistic Propositional Logic
-- using hereditary substitutions.
-- Andreas Abel, 21 May 2018
module NormalizationIPL where
-- We assume a set of propositional variables aka atomic propositions.
postulate
  Base : Set
-- Propositional formulas
data Form : Set where
  Atom  : (P : Base) → Form    -- Atomic proposition
  True  : Form                 -- Truth
  False : Form                 -- Absurdity
  _∧_   : (A B : Form) → Form  -- Conjunction   -- \ wedge
  _∨_   : (A B : Form) → Form  -- Disjunction   -- \ vee
  _⇒_   : (A B : Form) → Form  -- Implication   -- \ r 2
-- Binding strength of connective in decreasing order
infixl 8 _∧_
infixl 7 _∨_
infixr 6 _⇒_
-- The propositional calculus defines how we can derive the truth
-- of a proposition C from a list of hypotheses Γ.
-- C is called the conclusion and Γ is also called the context
-- or the list of assumptions.
--
-- The propositional calculus allows us to make judgments
--
--   Γ ⊢ C
--
-- meaning "if all the assumptions in Γ are true, then C must be true as well".
-- To define this judgement and formal derivations of it, we first
-- formalize hypotheses.
-- Hypotheses are snoc-lists of formulas: most recent assumption is last.
-- We can also consider hypotheses as stacks of formulas.
data Cxt : Set where
  ε : Cxt                           -- Empty list  -- \ G e  ALT: \ epsilon
  _∙_ : (Γ : Cxt) (A : Form) → Cxt  -- Extension   -- \ .   and  \ G G for Γ
infixl 4 _∙_
-- The indexed type Hyp Γ A gives evidence that formula A is element
-- of the list of hypotheses Γ
data Hyp : (Γ : Cxt) (A : Form) → Set where
  top : ∀{Γ A}                 → Hyp (Γ ∙ A) A  -- Found A as the top element.
  pop : ∀{Γ A B} (x : Hyp Γ A) → Hyp (Γ ∙ B) A  -- Remove the top element, search on.
-- Derivations for the judgement Γ ⊢ C
-- These are the proof rules of intuitionistic propositional logic.
-- In type theory, we can define Γ ⊢ C as a set whose inhabitants
-- are the derivations of Γ ⊢ C.
-- Each element of the following list of constructors of Γ ⊢ C
-- represents one proof rule for IPL.  Each rule has a number of premises
-- (in our case, between 0 and 3), and a consequence.
-- For instance, the rule
--
--   Γ ⊢ A    Γ ⊢ B
--   -------------- andI
--   Γ ⊢ A ∧ B
--
-- has two premises, that A is derivable from Γ and B as well, and allows us
-- to conclude that A ∧ B is derivable as well.
-- We distinguish introduction rules, postfixed I, from elimination rules, postfixed E.
-- Introduction rules introduce a logical connective in the consequence, while
-- elimination rules eliminate a logical connective in one of the premises.
--
-- Above rule "andI" is an instance of an introduction rule, it constructs
-- evidence for a conjunction from evidence for each of the conjuncts.
-- An example for an elimination rule is:
--
--   Γ ⊢ A ∧ B
--   --------- andE₁
--   Γ ⊢ A
--
-- It allows us to conclude the derivability of the first conjunct, A, from
-- the derivability of the conjunction A ∧ B.
--
-- If an elimination rule has several premises, we call the one with
-- the eliminated connective the principal premise or main premise,
-- and its formula the principal or main formula, and the connective
-- the principal connective.
--
-- For example:
--
--   Γ ⊢ A ⇒ B    Γ ⊢ A
--   ------------------- impE
--   Γ ⊢ B
--
-- This rule, traditionally called "modus ponens", has principle connective ⇒,
-- principle formula A ⇒ B, and principal premise Γ ⊢ A ⇒ B.
-- The other premise, here, Γ ⊢ A, is called "side premise".
--
-- Some rules add a hypothesis to the context of a premise, for example,
-- the implication introduction rule:
--
--   Γ ∙ A ⊢ B
--   ---------- impI
--   Γ ⊢ A ⇒ B
--
-- This rule states that an implication A ⇒ B is derivable from hypotheses Γ,
-- if its conclusion B is derivable from the extended context Γ ∙ A.
--
-- Let's look at the Agda representation, and get explanations of
-- the remaining rules then.
infix 2 _⊢_  -- \ vdash
data _⊢_ (Γ : Cxt) : (A : Form) → Set where
  hyp    : ∀{A}     (x : Hyp Γ A)               → Γ ⊢ A
  trueI  : Γ ⊢ True
  andI   : ∀{A B}   (t : Γ ⊢ A)     (u : Γ ⊢ B) → Γ ⊢ A ∧ B
  andE₁  : ∀{A B}   (t : Γ ⊢ A ∧ B)             → Γ ⊢ A
  andE₂  : ∀{A B}   (t : Γ ⊢ A ∧ B)             → Γ ⊢ B
  impI   : ∀{A B}   (t : Γ ∙ A ⊢ B)             → Γ ⊢ A ⇒ B
  impE   : ∀{A B}   (t : Γ ⊢ A ⇒ B) (u : Γ ⊢ A) → Γ ⊢ B
  orI₁   : ∀{A B}   (t : Γ ⊢ A)                 → Γ ⊢ A ∨ B
  orI₂   : ∀{A B}   (t : Γ ⊢ B)                 → Γ ⊢ A ∨ B
  orE    : ∀{A B C} (t : Γ ⊢ A ∨ B) (u : Γ ∙ A ⊢ C) (v : Γ ∙ B ⊢ C) → Γ ⊢ C
  falseE : ∀{C}     (t : Γ ⊢ False) → Γ ⊢ C
-- Explanation:
--
-- hyp:    Γ ⊢ A is derivable since A ∈ Γ.
-- trueI:  Truth is trivially derivable (empty conjunction).
-- orI:    If one of the disjuncts is derivable, so is the disjunction.
-- orE:    If a disjunction A ∨ B is derivable, we can use it to derive
--         an arbitrary formula C if we can derive C both from A and from B.
-- falseE: The empty disjunction.  Once we have derived False, everything
--         is true (ex falsum quod libet).
-- In the remainder of this file, we define normal forms
-- and prove the normalization theorem.
-- The following Flag indicates whether we deal with a
--
--   lin)    straight-line elimination using only impE and andE
--   branch) an elimination that ends in a orE or falseE
data Flag : Set where
  lin    : Flag  -- Just impE and andE
  branch : Flag  -- lin followed by a single orE or falseE
-- The following grammar defines normal derivations (Nf),
-- which are constructed from introductions and then
-- possibly an elimination from a hypothesis.
mutual
  -- Normal derivations (Nf = normal form).
  -- We can recursively apply introduction rules
  -- and then switch to elimination from a hypothesis.
  data Nf (Γ : Cxt) : (A : Form) → Set where
    trueI  : Nf Γ True
    impI   : ∀{A B}   (t : Nf (Γ ∙ A) B)        → Nf Γ (A ⇒ B)
    andI   : ∀{A B}   (t : Nf Γ A) (u : Nf Γ B) → Nf Γ (A ∧ B)
    orI₁   : ∀{A B}   (t : Nf Γ A)              → Nf Γ (A ∨ B)
    orI₂   : ∀{A B}   (t : Nf Γ B)              → Nf Γ (A ∨ B)
    hyp    : ∀{A C f} (x : Hyp Γ A) (es : Elims Γ A C f) → Nf Γ C
  -- Elims Γ A C f eliminates proposition A into C, using
  -- possibly several impE and andE steps first, and then
  -- possibly a final falseE or orE step.
  -- All side derivations are in Nf.
  data Elims (Γ : Cxt) : (A C : Form) (f : Flag) → Set where
    []     : ∀{A}                                             → Elims Γ A A lin
    _∷_    : ∀{A B C f} (e : Elim Γ A B) (es : Elims Γ B C f) → Elims Γ A C f
    falseE : ∀{C}                                             → Elims Γ False C branch
    orE    : ∀{A B C} (t₁ : Nf (Γ ∙ A) C) (t₂ : Nf (Γ ∙ B) C) → Elims Γ (A ∨ B) C branch
  -- Elim Γ A C contains single a single impE or andE elimination.
  data Elim (Γ : Cxt) : (A C : Form) → Set where
    impE : ∀{A B} (t : Nf Γ A) → Elim Γ (A ⇒ B) B
    andE₁ : ∀{A B} → Elim Γ (A ∧ B) A
    andE₂ : ∀{A B} → Elim Γ (A ∧ B) B
-- Normal derivations are trivially consistent:
-- There is no normal proof of False in the empty context.
nf-consistent : Nf ε False → ∀{A : Set} → A
nf-consistent (hyp () _)
-- The challenge is to show that Nf is still a complete proof system for IPL.
-- That means that whenever t : Γ ⊢ C, there exists also a normal derivation v : Nf Γ C.
-- This theorem is also called normalization, because it takes a proof t
-- and returns its normal form.
-- In the remainder of this file, we prove the normalization theorem.
-- Proving the normalization theorem amounts to supply the "missing rules" for Nf.
-- For instance, there is a rule impI on normal derivations, but no rule
--
--   impE : (t : Nf Γ (A ⇒ B)) (u : Nf Γ A) → Nf Γ B
--
-- We will show that this rule is admissible.  It can be shown by
-- lexicographic induction on (A, t).  However, the inductive argument
-- is not trivial, it requires us to define a normalizing substitution.
-- First, we show the admissibility of conjucntion and absurdity elimination
-- which are straightforward.
-- Conjunction elimination (andE₁!).
-- For admissibility of andE₁ on normal derivations, consider the cases
-- for t : Nf Γ (A ∧ B).
--
-- Either t is (andI t₁ t₂) with t₁ : Nf Γ A and t₂ : Nf Γ B.
-- In this case we just return t₁.
--
-- Otherwise t is (hyp x es) which means that the conjunction is
-- proven from hypothesis (x : Hyp Γ X) by eliminations
-- es : Elims Γ X (A ∧ B) f.
--
-- In this case, we would simply wish to append a andE₁ elimination
-- to es.  This is possible if f = lin.  In case f = Branch, we
-- have to distribute andE₁ to the branches.
-- For falseE, there are zero branches, and for orE, there
-- are two branches of type Nf (Γ ∙ _) (A ∧ B).
-- We turn these into Nf (Γ ∙ _) A by recursively applying andE₁!.
-- Since the branches are subterms of the original term t,
-- the recursion is valid (i.e., does not lead to infinite regression).
mutual
  andE₁! : ∀{Γ A B} → Nf Γ (A ∧ B) → Nf Γ A
  andE₁! (andI t₁ _) = t₁
  andE₁! (hyp x es) = hyp x (andElims₁ es)
  andElims₁ : ∀ {Γ X A B f} (es : Elims Γ X (A ∧ B) f) → Elims Γ X A f
  andElims₁ (e ∷ es)    = e ∷ andElims₁ es
  andElims₁ []          = andE₁ ∷ []
  andElims₁ falseE      = falseE
  andElims₁ (orE t₁ t₂) = orE (andE₁! t₁) (andE₁! t₂)
-- Admissibility of andE₂ is analogous.
mutual
  andE₂! : ∀{Γ A B} → Nf Γ (A ∧ B) → Nf Γ B
  andE₂! (andI _ t₂) = t₂
  andE₂! (hyp x es) = hyp x (andElims₂ es)
  andElims₂ : ∀ {Γ X A B f} (es : Elims Γ X (A ∧ B) f) → Elims Γ X B f
  andElims₂ (e ∷ es)    = e ∷ andElims₂ es
  andElims₂ []          = andE₂ ∷ []
  andElims₂ (falseE)    = falseE
  andElims₂ (orE t₁ t₂) = orE (andE₂! t₁) (andE₂! t₂)
-- Absurdity elimination (falseE!).
-- The only normal derivation of False is from a hypothesis X
-- using eliminations es : Elims Γ X False f.
-- To eliminate False into a proposition A, we append falseE
-- to es if f = Lin, or distribute it over the brances if
-- f = branch.
mutual
  falseE! : ∀ {Γ A} → Nf Γ False → Nf Γ A
  falseE! (hyp x es) = hyp x (falseElims es)
  falseElims : ∀ {Γ X A f} → Elims Γ X False f → Elims Γ X A branch
  falseElims (e ∷ es)    = e ∷ falseElims es
  falseElims []          = falseE
  falseElims falseE      = falseE
  falseElims (orE t₁ t₂) = orE (falseE! t₁) (falseE! t₂)
-- First we have to prove some basic properties, for instance
-- that normal derivations are stable under context extensions
-- and permutations.
-- Renaming
-- If we can prove C from a context Δ we can also prove it
-- from Γ if every hypothesis in Δ can also be found in Γ.
-- Thus, Γ can be a permutation of Δ or extension of Δ or both.
-- A "renaming" r : Ren Γ Δ is a map from the hypotheses of Δ
-- to the hypotheses of Γ.
--
-- If we apply r to an address x : Hyp Δ A of hypothesis A in Δ,
-- we get the address r x : Hyp Γ A of this hypothesis in Γ.
Ren : (Γ Δ : Cxt) → Set
Ren Γ Δ = ∀{A} → Hyp Δ A → Hyp Γ A
-- A renaming r from Δ to Γ can be lifted to a renaming
-- liftr r from Δ ∙ A to Γ ∙ A which leaves the position
-- of the new hypothesis A unchanged on the top.
liftr : ∀{Γ Δ A} (r : Ren Γ Δ) → Ren (Γ ∙ A) (Δ ∙ A)
liftr r top     = top
liftr r (pop x) = pop (r x)
-- The following mutual functions prove that Nf, Elim, and Elims
-- are stable under renaming.
-- This is a routine induction.  Whenever we go under a binder,
-- like in impI or orE, we need to lift the renaming
-- to account for the new hypothesis.
mutual
  ren : ∀{Γ Δ A} (r : Ren Γ Δ) (t : Nf Δ A) → Nf Γ A
  ren r (hyp x es) = hyp (r x) (renElims r es)
  ren r trueI      = trueI
  ren r (impI t)   = impI (ren (liftr r) t)
  ren r (andI t u) = andI (ren r t) (ren r u)
  ren r (orI₁ t)   = orI₁ (ren r t)
  ren r (orI₂ t)   = orI₂ (ren r t)
  renElims : ∀{Γ Δ A B f} (r : Ren Γ Δ) (es : Elims Δ A B f) → Elims Γ A B f
  renElims r []          = []
  renElims r (e ∷ es)    = renElim r e ∷ renElims r es
  renElims r falseE      = falseE
  renElims r (orE t₁ t₂) = orE (ren (liftr r) t₁) (ren (liftr r) t₂)
  renElim : ∀{Γ Δ A B} (r : Ren Γ Δ) (e : Elim Δ A B) → Elim Γ A B
  renElim r (impE t) = impE (ren r t)
  renElim r andE₁    = andE₁
  renElim r andE₂    = andE₂
-- We will need the following three instances of renaming,
-- called weakenings.  These add an unused hypothesis on top
-- (weak and weakElim) or just below the top (weak').
weak : ∀{Γ A C} (t : Nf Γ C) → Nf (Γ ∙ A) C
weak = ren pop
weakElim : ∀{Γ A B C} (e : Elim Γ B C) → Elim (Γ ∙ A) B C
weakElim = renElim pop
weak' : ∀{Γ A B C} (t : Nf (Γ ∙ B) C) → Nf (Γ ∙ A ∙ B) C
weak' = ren (liftr pop)
-- Hereditary substitution.
-- When showing the admissibility of
--
--   impE : (t : Nf Γ (A ⇒ B)) (u : Nf Γ A) → Nf Γ B
--
-- we have to treat the case that t = impI t' with
-- t' : Nf (Γ ∙ A) B.   How do we get a Nf Γ B?
-- We substitute all uses of the top hypothesis in t' by u.
--
-- However, if A is not an atomic proposition,
-- this hypothesis might be under eliminations es,
-- thus, we have to normalize the elimination of u by es.
-- This might in turn trigger a substitution, for instance,
-- if u is itself an impI u' and the first elimination of es
-- is an impE v.
--
-- Thus, a substitution might trigger new substitutions,
-- and this process is called "hereditary substitution(s)".
-- How can we be sure this process ever terminates?
-- It turns out at all subsequent substitutions triggered
-- by a substitution of u : Nf Γ A for a hypothesis x : Hyp Γ A,
-- are substitutions of a u' : Nf Γ' A' for an a' : Hyp Γ' A',
-- where A' is a subproposition of A.
-- Thus, we can define substitution of u : Nf Γ A into t' : Nf (Γ ∙ A) B
-- by an outer recursion on A and an inner recursion on t'.
-- As a first step, we define the type of substitutions
-- Sub A Γ Δ of a Nf Γ A into something in context Γ.
-- Such a substitution replaces each hypothesis Hyp Δ C
-- by a "result" Res A Γ C where the result can be a
-- Nf Γ A if A = C and must be a hypothesis otherwise.
data Res A Γ : (C : Form) → Set where
  rnf  : (t : Nf Γ A) → Res A Γ A
  rhyp : ∀{C} (x : Hyp Γ C) → Res A Γ C
Sub : (A : Form) (Γ Δ : Cxt) → Set
Sub A Γ Δ = ∀{C} → Hyp Δ C → Res A Γ C
-- Routinely, we prove that results can be weakened.
weakRes : ∀{Γ A B C} (t : Res A Γ C) → Res A (Γ ∙ B) C
weakRes (rnf  t) = rnf (weak t)
weakRes (rhyp x) = rhyp (pop x)
-- We construct substitutions by the following two methods.
-- A singleton substitution sg t is constructed from a single normal form t.
-- It replaces the top hypothesis by t and all other hypotheses by themselves.
sg : ∀ {Γ A} (t : Nf Γ A) → Sub A Γ (Γ ∙ A)
sg t top     = rnf t
sg t (pop x) = rhyp x
-- We can lift a substitution to one more hypothesis which remains fixed.
lift : ∀{A Γ Δ B} (s : Sub A Γ Δ) → Sub A (Γ ∙ B) (Δ ∙ B)
lift s top     = rhyp top
lift s (pop x) = weakRes (s x)
-- Substitution of (s : Sub A Γ Δ) into normal forms (t : Nf Δ C)
-- is now defined by lexicographic induction on (A, t),
-- mutually with many auxiliary functions like substitution
-- into eliminations, elimination of a normal form,
-- and admissiblity of impE and orE for normal forms.
-- Thanks to the dependent typing, most cases are forced.
-- And Agda's termination checker scrutinizes our definition,
-- to ensure correct use of the induction hypotheses.
mutual
  -- Substitution is homeomorphic except for the case (hyp x es)
  -- in which we have to apply the substitution s to hypothesis x
  -- and eliminate the result by es.
  subst : ∀ A {Γ Δ} (s : Sub A Γ Δ) {C} (t : Nf Δ C) → Nf Γ C
  subst A s trueI        = trueI
  subst A s (impI t)     = impI (subst A (lift s) t)
  subst A s (andI t₁ t₂) = andI (subst A s t₁) (subst A s t₂)
  subst A s (orI₁ t)     = orI₁ (subst A s t)
  subst A s (orI₂ t)     = orI₂ (subst A s t)
  subst A s (hyp x es)   = elimsRes A (s x) (substElims A s es)
  substElims : ∀ A {Γ Δ} (s : Sub A Γ Δ) {B C f} (es : Elims Δ B C f) → Elims Γ B C f
  substElims A s []          = []
  substElims A s (e ∷ es)    = substElim A s e ∷ substElims A s es
  substElims A s falseE      = falseE
  substElims A s (orE t₁ t₂) = orE (subst A (lift s) t₁) (subst A (lift s) t₂)
  substElim : ∀ A {Γ Δ} (s : Sub A Γ Δ) {B C} (e : Elim Δ B C) → Elim Γ B C
  substElim A s (impE t) = impE (subst A s t)
  substElim A s andE₁    = andE₁
  substElim A s andE₂    = andE₂
  -- If the result of substituting x is just an hypothesis y,
  -- we can just put the eliminations es back.
  -- Otherwise, if the result is a normal form t, we have
  -- to eliminate it recursively by es.
  -- This might trigger new substitutions in cases impE or orE.
  elimsRes : ∀ A {Γ B C f} (r : Res A Γ B) (es : Elims Γ B C f) → Nf Γ C
  elimsRes A (rhyp y) es = hyp y es
  elimsRes A (rnf t) es = elims A t es
  -- "elims" is the place where types are actually getting smaller
  -- but terms might get bigger by invokation of impE! and orE!.
  elims : ∀ A {Γ C f} (t : Nf Γ A) (es : Elims Γ A C f) → Nf Γ C
  elims A        t []                    = t
  elims .(A ⇒ B) t (impE {A} {B} u ∷ es) = elims B (impE! A t u) es
  elims .(A ∧ B) t (andE₁ {A} {B}  ∷ es) = elims A (andE₁! t) es
  elims .(A ∧ B) t (andE₂ {A} {B}  ∷ es) = elims B (andE₂! t) es
  elims .False   t falseE                = falseE! t
  elims .(A ∨ B) t (orE {A} {B} t₁ t₂)   = orE! A B t t₁ t₂
  -- The admissible eliminations of implication and disjunction,
  -- impE! and orE!, are invoked by "elims" and in turn invoke
  -- substitution.  It is crucial that they are called with
  -- a strictly smaller proposition than the original call to subst had.
  -- Implication elimination
  -- Triggers new substitutions in case of (impI t).  In the other case,
  -- we append the (impE u) to the eliminations es, distributing it to the
  -- branches in case of falseE or orE.
  impE! : ∀ A {Γ B} (t : Nf Γ (A ⇒ B)) (u : Nf Γ A) → Nf Γ B
  impE! A (impI t)   u = subst A (sg u) t
  impE! A (hyp x es) u = hyp x (impElims A es u)
  impElims : ∀ A {Γ B X f} (es : Elims Γ X (A ⇒ B) f) (u : Nf Γ A) → Elims Γ X B f
  impElims A (e ∷ es) u    = e ∷ impElims A es u
  impElims A [] u          = impE u ∷ []
  impElims A (falseE) u    = falseE
  impElims A (orE t₁ t₂) u = orE (impE! A t₁ (weak u)) (impE! A t₂ (weak u))
  -- Disjunction elimination
  -- Triggers new substitutions in case of orI.  Otherwise, append
  -- an orE to the eliminations, possibly distributing it to the branches.
  orE! : ∀ A B {Γ C} (t : Nf Γ (A ∨ B)) (u : Nf (Γ ∙ A) C) (v : Nf (Γ ∙ B) C) → Nf Γ C
  orE! A B (orI₁ t)   u v = subst A (sg t) u
  orE! A B (orI₂ t)   u v = subst B (sg t) v
  orE! A B (hyp x es) u v = hyp x (orElims A B es u v)
  orElims : ∀ A B {Γ C X f} (es : Elims Γ X (A ∨ B) f)
    (u : Nf (Γ ∙ A) C)
    (v : Nf (Γ ∙ B) C) → Elims Γ X C branch
  orElims A B (e ∷ es)    u v = e ∷ orElims A B es u v
  orElims A B []          u v = orE u v
  orElims A B (falseE)    u v = falseE
  orElims A B (orE t₁ t₂) u v = orE (orE! A B t₁ (weak' u) (weak' v))
                                    (orE! A B t₂ (weak' u) (weak' v))
-- Normalization.
-- Finally, we can show that each derivation of Γ ⊢ A
-- also has a normal derivation.
--
-- The proof is by induction on the derivation, using
-- the admissible elimination rules to compose the
-- results of the induction hypotheses.
nf : ∀{Γ A} (t : Γ ⊢ A) → Nf Γ A
nf (hyp x)       = hyp x []
nf trueI         = trueI
nf (andI t u)    = andI (nf t) (nf u)
nf (andE₁ t)     = andE₁! (nf t)
nf (andE₂ t)     = andE₂! (nf t)
nf (impI t)      = impI (nf t)
nf (impE t u)    = impE! _ (nf t) (nf u)
nf (orI₁ t)      = orI₁ (nf t)
nf (orI₂ t)      = orI₂ (nf t)
nf (orE t t₁ t₂) = orE! _ _ (nf t) (nf t₁) (nf t₂)
nf (falseE t)    = falseE! (nf t)
-- QED -}
-- Acknowledgements.
--
-- I learned the trick of doing hereditary substitutions by just
-- /structural/ recursion on types from Conor McBride.
-- He sent me some Agda code that accomplished this for the STLC using
-- the left-to-right elimination vectors we extended here to sum types.
--
-- I could have learned it from Felix Joachimski and Ralph Matthes
-- as well.  The normalization algorithm presented here should be
-- the computational content of their strong normalization proof
-- for lambda-calculus with permutative conversions (AML 2003).
-- However, I did not have the formalization skills back then
-- I have now to translate their generous vector notation into
-- the statically well-typed Elims.
-- Literature.
-- Dag Prawitz:
--   Natural Deduction: A Proof-Theoretical Study
--   Dover Publications (1965)
-- Felix Joachimski, Ralph Matthes:
--   Short proofs of normalization for the simply-typed lambda-calculus,
--   permutative conversions and Gödel's T.
--   Arch. Math. Log. 42(1): 59-87 (2003)
-- Kevin Watkins, Iliano Cervesato, Frank Pfenning, David Walker:
--   A concurrent logical framework {I}: Judgements and properties.
--   Technical report CMU-CS02-101,
--   School of Computer Science, Carnegie Mellon University, Pittsburgh (2003)
-- Andreas Abel:
--   Implementing a normalizer using sized heterogeneous types.
--   J. Funct. Program. 19(3-4): 287-310 (2009)
-- Chantal Keller, Thorsten Altenkirch:
--   Hereditary Substitutions for Simple Types, Formalized.
--   MSFP@ICFP 2010: 3-10
-- Harley D. Eades III, Aaron Stump
--   Exploring the Reach of Hereditary Substitution.
--   International Conference on Types for Proofs and Programs, TYPES 2011, Bergen, Norway.
--   Abstract: https://sites.google.com/site/types2011/program/types2011-talkswabstracts#Eades
--   Talk:     http://metatheorem.org/includes/talks/2012-TYPES.pdf
--   Paper:    http://metatheorem.org/includes/pubs/TYPES-2012.pdf