# Theory Tait

Up to index of Isabelle/HOL/Tait

theory Tait
imports Main
begin

(*<*)
theory Tait = Main:
(*>*)

text {*
In this section, we will compare the Coq and Minlog formalizations
of the normalization proof with a formalization in the theorem prover
Isabelle/HOL. We start by giving the definition of types and terms:
*}

(*<*)
lemma cheating: "PROP P" sorry

typedecl name

consts inj_name :: "nat => name"          ("\<sharp> _" 100)

lemma name_eq_dec: "((n::name) = n') ∨ (n ≠ n')"
sorry

consts
name_eq_dec :: "name => name => sumbool"

realizers
name_eq_dec: "name_eq_dec" "cheating · _"
(*>*)
datatype type =
Iota
| Arrow type type         (infix "\<rightharpoonup>" 80)

datatype trm =
Var name        ("´_" 90)
| App trm trm     (infix "¨" 80)
| Abs name trm    (" λ[_]._ " [70,70] 80)
(*<*)
types ctxt = "name => type"

types substitution = "name => trm"

constdefs
subst_id :: substitution
"subst_id x ≡ ´x"

constdefs
update :: "(name=>'a)=>name=>'a=>name=>'a"
"update f x a y ≡ if x=y then a else f y"

consts TypJ :: "(ctxt×trm×type)set"
syntax "_TypJ" :: "ctxt => trm => type => bool"   (" _ \<turnstile> _ : _" [80,80,80] 80)
translations " (ρs \<turnstile> r : ρ)" \<rightleftharpoons> "(ρs,r,ρ) ∈ TypJ"
inductive TypJ
intros
Typ_Var : " ρs \<turnstile> ´x : ρs x"
Typ_Abs : "(update ρs x ρ) \<turnstile> r : σ ==>
ρs \<turnstile> λ[x].r : ρ\<rightharpoonup>σ"
Typ_App : "ρs \<turnstile> r : ρ\<rightharpoonup>σ  ==>
ρs \<turnstile> s : ρ  ==>
ρs \<turnstile> r¨s : σ"

consts sub :: "trm => substitution => trm" (infix "•" 70)

axioms sub_Var : "(´x)•ϑ == ϑ x"
axioms sub_App : "(r¨s)•ϑ == (r•ϑ)¨(s•ϑ)"
axioms sub_id :  "r•subst_id = r"

consts F :: "trm => nat => bool"
consts N :: "trm => trm => bool"
consts A :: "trm => trm => bool"
consts H :: "trm => trm => bool"

constdefs
SN :: "trm => bool"
"SN r ≡ ∀k. F r k --> (∃s. N r s)"
SA :: "trm => bool"
"SA r ≡ ∀k. F r k --> (∃s. A r s)"
(*>*)

text {*
The judgement stating that @{term t} has type @{term "τ"} in context
@{term "ρs"} is denoted by \mbox{@{term "ρs \<turnstile> t : τ"}}. The definition of
the typing judgement is as usual.
In contrast to Minlog, Isabelle/HOL allows the definition of predicates
by recursion over datatypes (also called strong elimination'' in Coq
jargon). Thus, we can simply define @{text SC} by recursion over the
datatype @{text type}:
*}

consts SC :: "type => trm => bool"
primrec
SC_Atom: "SC Iota r = SN r"
SC_Fun: "SC (ρ\<rightharpoonup>σ) r = (∀s. (SC ρ s) --> (SC σ (r¨s)))"
(*<*)
declare SN_def [extraction_expand]
declare SA_def [extraction_expand]
(*>*)

text {*
However, when it comes to extracting a program from a proof involving
@{text SC}, we face a problem: Since predicates in a proof become types
in the extracted program, predicates such as @{text SC} defined by recursion
on datatypes give rise to programs using dependent types. Such programs
can neither be expressed inside Isabelle/HOL, nor can they easily be
translated to functional programming languages such as ML. In order
to get a program which is typable in a functional programming language
without dependent types, we realize the formula @{term "SC τ t"} by
a datatype @{text D} with two constructors @{term "Term"} and @{term "Func"}.
The former corresponds to the case where @{term "τ"} is a base type,
whereas the latter corresponds to the case where @{term "τ"} is a
function type. In ML, one would define the datatype @{text D} as follows:
\begin{verbatim}
datatype D = Term of nat -> trm | Func of trm -> D -> D
\end{verbatim}
This datatype is beyond the scope of Isabelle/HOL, since @{text D}
occurs {\it negatively} in the argument type of @{text Func}.
It is interesting to note that in the logic HOLCF, which is a conservative
extension of HOL with LCF, one can actually define the above datatype,
provided that the type of partial continuous functions is used instead
of the type of total functions.
For the moment, we just assert the existence of type @{text D}, together
with suitable constructors:
*}

typedecl D

consts
Term :: "(nat => trm) => D"
Func :: "(trm => D => D) => D"
destTerm :: "D => nat => trm"
destFunc :: "D => trm => D => D"
(*<*)
realizes_SC :: "D => type => trm => bool"

extract_type
"typeof (SC T t) ≡ Type (TYPE(D))"

realizability
"(realizes e (SC T t)) ≡ (realizes_SC e T t)"
(*>*)

text {*
Here, @{term destTerm} and @{term destFunc} are {\it destructors}
corresponding to the constructors of the datatype @{text D}. These
can be implemented using pattern matching. We can now assign
realizing terms to the two characteristic equations for @{term SC}.
Since we can view an equation between propositions as a conjunction
of two implications, the equations for @{term SC} are realized
by pairs, of which the first component is a destructor, and the second
component is a constructor:
*}

realizers
SC_Atom: "λ t. (destTerm, Term)" (*<*) "cheating · _" (*>*)

SC_Fun: "λ ρ σ t. (destFunc, Func)" (*<*) "cheating · _" (*>*)
(*<*)
axioms
Ax1 : "F r k ==>
N (r¨´\<sharp>k) t ==>
N r (λ[\<sharp>k].t)"
Ax2 : "A r s ==> N r s"
Ax3 : "A (´x) (´x)"
Ax4 : "A r r' ==> N s s' ==> A (r¨s) (r'¨s')"
Ax5 : "H r s ==> N s t ==> N r t"
Ax6 : "SN s ==> H (((λ[x].r)•ϑ)¨s) (r•(update ϑ x s))"
Ax7 : "H r s ==> H (r¨t) (s¨t)"
Ax8 : "F r k ==> F (r¨´\<sharp>k) (Suc k)"
Ax9 : "F (r¨s) k ==> F s k"
Ax10 : "F (r¨s) k ==> F r k"
Ax11 : "F r k ==> H r s ==> F s k"

lemma Ax6_corr:
"∀k. F s k --> N s (f k) ==> H (((λ[x].r)•ϑ)¨s) (r•(update ϑ x s))"
apply (rule Ax6)
done

realizers
Ax6: "Null" "Λ s x r ϑ f. Ax6_corr · _ · _ · _ · _ · _"
(*>*)

text {*
The proof of strong normalization is composed of the following parts:
*}

lemma One : "∀r. (SC ρ r --> SN r) ∧ (SA r --> SC ρ r)"
(*<*)
apply (induct_tac ρ)
apply simp
apply (intro impI allI)
apply (rules intro:Ax2)
(* old manual proof: *)
(*apply (rule impI, drule mp, assumption)*)
(*apply (erule exE)+*)
(*apply (rule exI, rule Ax2, assumption)*)
(* or apply (rule_tac x="x" in exI) for an explicit instantiation *)

apply (intro allI conjI impI)
apply (erule exE)
apply (subgoal_tac "SA (´\<sharp>k)") prefer 2
apply (subgoal_tac "SN (r¨´\<sharp>k)") prefer 2
apply (rules)
apply (simp only:SN_def)
apply (drule_tac x="Suc k" in spec)
apply (drule mp)
apply (rule Ax8, assumption)
apply (erule exE)
apply (rule exI, rule Ax1, rules, assumption)

apply (drule_tac x="r¨s" in spec)
back
apply (rule conjE,assumption)
apply (rule mp,assumption)
apply (rule impI, erule exE)
apply (subgoal_tac "SN s") prefer 2
apply (rules)
apply (simp only:SN_def)
apply (drule_tac x="k" in spec)
apply (drule mp,rule Ax9,assumption)
apply (erule exE)
apply (simp only:SA_def)
apply (drule_tac x="k" in spec)
apply (drule mp,rule Ax10,assumption)
apply (erule exE)
apply (rule exI, rule Ax4, rules, assumption)
done
(*>*)

lemma Two : "∀r r'. SC ρ r' --> H r r' --> SC ρ r"
(*<*)
apply (induct_tac ρ)
apply (rules intro:Ax5 intro:Ax11)
apply (rule allI)+
apply (simp (no_asm_use))
apply (rule impI allI)+
apply (rules intro:Ax7)
done

lemma spec3 [extraction_expand]: "∀x y z. P x y z ==> P x y z"
apply rules
done

lemma app_type_elim:
"Γ \<turnstile> r ¨ s : ρ ==> ∃ σ . (Γ \<turnstile> r : (σ \<rightharpoonup> ρ)) ∧  Γ \<turnstile> s : σ"
by (ind_cases "ρs \<turnstile> trm1 ¨ trm2 : ρ") auto

consts
app_type_elim :: "ctxt => trm => trm => type => type"

realizers
app_type_elim: "app_type_elim" "cheating · _"

lemma abs_type_elim:
"Γ \<turnstile> λ[x]. t : ρ ==> ∃ σ σ' . ρ = (σ \<rightharpoonup> σ') ∧ update Γ x σ \<turnstile> t : σ'"
apply (cases "ρ")
apply (rule FalseE)
apply (ind_cases "Γ \<turnstile> λ[x]. t : ρ")
apply simp
apply (rule_tac x=type1 in exI)
apply (rule_tac x=type2 in exI)
apply (ind_cases "Γ \<turnstile> λ[x]. t : ρ")
apply simp
done

lemma var_type_elim: "ρs \<turnstile> ´x : ρ ==> ρ = ρs x"
by (ind_cases "ρs \<turnstile> ´x : ρ") simp
(*>*)

lemma Three : "∀ρs ϑ ρ. ρs \<turnstile> r : ρ  --> (∀z. SC (ρs z) (ϑ z)) --> SC ρ (r•ϑ)"
(*<*)
apply (induct_tac r)
apply (rename_tac x)
apply (rule allI impI)+
apply (drule var_type_elim)
apply simp

apply (rule allI impI)+
apply (drule app_type_elim)
apply (erule exE conjE)+
apply (drule_tac x=ρs and y=ϑ and z="σ \<rightharpoonup> ρ" in spec3)
apply (simp)

apply (rule allI impI)+
apply (drule abs_type_elim)
apply (erule exE conjE)+
apply simp
apply (rule allI impI)+
apply (rule Two[THEN spec, THEN spec, THEN mp, THEN mp])
defer
apply (rule Ax6)
apply (rule One[THEN spec, THEN conjunct1, THEN mp], assumption)
apply (drule_tac x="update ρs name σ" and y="update ϑ name s" in spec3)
apply (drule mp, assumption, drule mp) defer apply (assumption)
apply (rule allI)
apply (cut_tac n="name" and n'="z" in name_eq_dec)
apply (erule disjE)
done
(*>*)

lemma Norm: "∀ ρs ρ r. ρs \<turnstile> r : ρ --> (∀k. F r k --> (∃s. N r s))" (*<*)
apply (rule allI impI)+
apply (subgoal_tac "SC ρ (r•subst_id)") defer
apply (rule Three[THEN spec, THEN spec, THEN spec, THEN mp, THEN mp])
apply (assumption)
apply (rule allI)
apply (rule One[THEN spec, THEN conjunct2, THEN mp])
apply (rules intro:Ax3)
apply (subgoal_tac "SN r") defer
apply (rule One[THEN spec, THEN conjunct1, THEN mp], assumption)
done

declare all_simps [extraction_expand]

extract Norm
(*>*)
text {*
The computationally relevant predicates @{term "SN"} and @{term "SA"} are
defined by
@{thm [display] SN_def [no_vars] SA_def [no_vars]}
The programs extracted from the above theorems have the types
\begin{center}
\begin{tabular}{ll}
@{text "One:"} & @{typeof [unique_names=false] One} \\
@{text "Two:"} & @{typeof [unique_names=false] Two} \\
@{text "Three:"} & \begin{minipage}[t]{8cm} @{typeof [unique_names=false,break,margin=60] Three} \end{minipage} \\
@{text "Norm:"} & @{typeof [unique_names=false] Norm}
\end{tabular}
\end{center}
They are defined as follows:
@{thm [display] One_def[simplified]}
@{thm [display] Two_def[simplified]}
@{thm [display] Three_def[simplified]}
@{thm [display] Norm_def}
Due to the lack of non-computational quantifiers in Isabelle, the
above programs contain typing information for the term to be
normalized, which is unnecessary for the computation.
In particular, the extracted programs use auxiliary functions
corresponding to the elimination rules
\begin{center}
\begin{tabular}{ll}
@{text "var_type_elim:"} & @{thm var_type_elim [no_vars]} \\
@{text "abs_type_elim:"} & \begin{minipage}[t]{8cm} @{thm [break,margin=60] abs_type_elim [no_vars]} \end{minipage} \\
@{text "app_type_elim:"} & @{thm app_type_elim [no_vars]} \\
\end{tabular}
\end{center}
for the typing judgement.
It turns out that all typing information can be omitted from function
@{text Three}. This may seem a bit surprising, since @{text Three} calls
function @{text Two}, which is defined by recursion on types. However,
a closer look reveals that @{text Two} is actually just a complicated
formulation of the identity function and can therefore be omitted.
Unfortunately, Isabelle's program extraction framework cannot detect
this automatically.
*}

(*<*)
end
(*>*)


lemma cheating:

  PROP P  [!]

lemma name_eq_dec:

  n = n' ∨ n ≠ n'  [!]

lemma Ax6_corr:

  ∀k. F s k --> N s (f k) ==> H (( λ[x].r  • ϑ) ¨ s) (r • update ϑ x s)

lemma One:

  ∀r. (SC ρ r --> SN r) ∧ (SA r --> SC ρ r)

lemma Two:

  ∀r r'. SC ρ r' --> H r r' --> SC ρ r

lemma spec3:

  ∀x y z. P x y z ==> P x y z

lemma app_type_elim:

   Γ \<turnstile> r ¨ s : ρ
==> ∃σ.  Γ \<turnstile> r : σ \<rightharpoonup> ρ ∧  Γ \<turnstile> s : σ
[!]

lemma abs_type_elim:

   Γ \<turnstile>  λ[x].t  : ρ
==> ∃σ σ'. ρ = σ \<rightharpoonup> σ' ∧  update Γ x σ \<turnstile> t : σ'
[!]

lemma var_type_elim:

   ρs \<turnstile> ´x : ρ ==> ρ = ρs x  [!]

lemma Three:

  ∀ρs ϑ ρ.  ρs \<turnstile> r : ρ --> (∀z. SC (ρs z) (ϑ z)) --> SC ρ (r • ϑ)  [!]

lemma Norm:

  ∀ρs ρ r.  ρs \<turnstile> r : ρ --> (∀k. F r k --> (∃s. N r s))  [!]