Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use instead of Ctrl.

Lecture 11: Termination

In this lecture, we will prove that the simply typed lambda calculus is terminating. We also add natural numbers to the language.

Here, we demonstrate the use of the Rec operator in Coq. Our language will also have such a Rec operator. The Rec operator is powerful enough to define addition, multiplication, and exponentiation.

Fixpoint rec {A} (n : nat) (x : A) (f : A -> A) : A :=
  match n with
  | 0 => x
  | S n => f (rec n x f)
  end.

Definition double n := rec n 0 (fun x => S (S x)).

= 6 : nat
Definition add n m := rec n m (fun x => S x).
= 7 : nat
Definition mul n m := rec n 0 (fun x => add m x).
= 12 : nat
Definition pow n m := rec m 1 (fun x => mul n x).
= 8 : nat

When using rec with A := nat, we can only do primitive recursion. By using the rec operator at type A := nat -> nat, we can go beyond, and define the Ackermann function.

Definition ack m := rec m S (fun f => fun n => rec (S n) 1 f).

= 61 : nat
(* Useful tactics for simplifying equalities *) Ltac simpeq := repeat match goal with | _ => congruence || (progress subst) | H : ?x = ?x |- _ => clear H | H : _ = _ |- _ => progress injection H as H end. Ltac inv H := inversion H; clear H; simpeq. (* Utilities on environments/contexts *)
[Loading ML file ring_plugin.cmxs (using legacy method) ... done]
Definition empty {T} : string -> option T := fun _ => None. Definition insert {T} (x : string) (t : T) (f : string -> option T) : string -> option T := fun x' => if string_dec x x' then Some t else f x'. Definition delete {T} (x : string) (f : string -> option T) : string -> option T := fun x' => if string_dec x x' then None else f x'. (* fun_eq lets us avoid the function extensionality axiom *) Definition fun_eq {A B} (f g : A -> B) := forall x, f x = g x. Notation "f == g" := (fun_eq f g) (at level 70). Ltac simpfun := (unfold fun_eq, delete, insert in *); (repeat (solve [eauto] || destruct string_dec || simpeq || intro)). (* We can prove all the following lemmas using simpfun. Now that we have simpfun, we don't even need the lemmas, we can just do simpfun. Lemma fun_eq_refl {A B} (f : A -> B) : f == f. Proof. simpfun. Defined. Lemma fun_eq_sym {A B} (f g : A -> B) : f == g -> g == f. Proof. simpfun. Defined. Lemma delete_insert {T} x v (env : string -> option T) : delete x (insert x v env) == delete x env. Proof. simpfun. Defined. Lemma insert_delete {T} x v (env : string -> option T) : insert x v (delete x env) == insert x v env. Proof. simpfun. Defined. Lemma delete_delete {T} x (env : string -> option T) : delete x (delete x env) == delete x env. Proof. simpfun. Defined. Lemma delete_delete_comm {T} x y (env : string -> option T) : x <> y -> delete x (delete y env) == delete y (delete x env). Proof. simpfun. Defined. Lemma delete_insert_comm {T} x y v (env : string -> option T) : x <> y -> delete x (insert y v env) == insert y v (delete x env). Proof. simpfun. Defined. *)

Syntax

Inductive expr :=
  | Var (x : string)
  | Lam (x : string) (e : expr)
  | App (e1 e2 : expr)
  | Zero : expr
  | Succ (e : expr)
  | Rec (e1 e2 e3 : expr).

Typing

Inductive ty :=
  | Nat : ty
  | Fun (t1 t2 : ty).

Definition ctx := string -> option ty.

Inductive typed : ctx -> expr -> ty -> Prop :=
  | Typed_Var (x : string) (t : ty) (Gamma : ctx) :
    Gamma x = Some t ->
    typed Gamma (Var x) t
  | Typed_Lam (x : string) (e : expr) (t1 t2 : ty) (Gamma : ctx) :
    typed (insert x t1 Gamma) e t2 ->
    typed Gamma (Lam x e) (Fun t1 t2)
  | Typed_App (e1 e2 : expr) (t1 t2 : ty) (Gamma : ctx) :
    typed Gamma e1 (Fun t1 t2) ->
    typed Gamma e2 t1 ->
    typed Gamma (App e1 e2) t2
  | Typed_Zero (Gamma : ctx) :
    typed Gamma Zero Nat
  | Typed_Succ (e : expr) (Gamma : ctx) :
    typed Gamma e Nat ->
    typed Gamma (Succ e) Nat
  | Typed_Rec (e1 e2 e3 : expr) (Gamma : ctx) (t : ty) :
    typed Gamma e1 Nat ->
    typed Gamma e2 t ->
    typed Gamma e3 (Fun t t) ->
    typed Gamma (Rec e1 e2 e3) t.

Semantics

Substitution

Fixpoint subst (x : string) (v : expr) (e : expr) : expr :=
  match e with
  | Var y => if string_dec x y then v else e
  | Lam y e => Lam y (if string_dec x y then e else subst x v e)
  | App e1 e2 => App (subst x v e1) (subst x v e2)
  | Zero => Zero
  | Succ e => Succ (subst x v e)
  | Rec e1 e2 e3 => Rec (subst x v e1) (subst x v e2) (subst x v e3)
  end.

Values

Inductive value : expr -> Prop :=
  | Val_Lam (x : string) (e : expr) :
    value (Lam x e)
  | Val_Zero :
    value Zero
  | Val_Succ (e : expr) :
    value e ->
    value (Succ e).

Small-step Semantics

Inductive step : expr -> expr -> Prop :=
  | Step_App1 (e1 e1' e2 : expr) :
    step e1 e1' ->
    step (App e1 e2) (App e1' e2)
  | Step_App2 (e1 e2 e2' : expr) :
    step e2 e2' ->
    step (App e1 e2) (App e1 e2')
  | Step_AppLam (x : string) (v e : expr) :
    value v ->
    step (App (Lam x e) v) (subst x v e)
  | Step_Succ1 (e e' : expr) :
    step e e' ->
    step (Succ e) (Succ e')
  | Step_Rec1 (e1 e1' e2 e3 : expr) :
    step e1 e1' ->
    step (Rec e1 e2 e3) (Rec e1' e2 e3)
  | Step_Rec2 (e1 e2 e2' e3 : expr) :
    step e2 e2' ->
    step (Rec e1 e2 e3) (Rec e1 e2' e3)
  | Step_Rec3 (e1 e2 e3 e3' : expr) :
    step e3 e3' ->
    step (Rec e1 e2 e3) (Rec e1 e2 e3')
  | Step_RecZero (e2 e3 : expr) :
    value e2 -> value e3 ->
    step (Rec Zero e2 e3) e2
  | Step_RecSucc (e1 e2 e3 : expr) :
    value e1 -> value e2 -> value e3 ->
    step (Rec (Succ e1) e2 e3) (Rec e1 (App e3 e2) e3).

Termination

Inductive rtc {A} (R : A -> A -> Prop) : A -> A -> Prop :=
  | rtc_refl (x : A) : rtc R x x
  | rtc_once (x y z : A) : R x y -> rtc R y z -> rtc R x z.

Definition terminates (e : expr) :=
  exists e', rtc step e e' /\ value e'.

Termination proof

(* Main proof: semantic typing of values and expressions *)

Fixpoint nat_to_expr (n : nat) : expr :=
  match n with
  | 0 => Zero
  | S n => Succ (nat_to_expr n)
  end.

Definition closed e := forall x v, subst x v e = e.

Fixpoint value_ok (e : expr) (t : ty) :=
  match t with
  | Nat => exists n, e = nat_to_expr n
  | Fun t1 t2 =>
      closed e /\
      exists x ebody, e = Lam x ebody /\
        forall v, value_ok v t1 ->
          exists e', rtc step (subst x v ebody) e' /\ value_ok e' t2
  end.

Definition expr_ok (e : expr) (t : ty) :=
  exists e', rtc step e e' /\ value_ok e' t.


(* Helper lemmas about steps, value_ok, and expr_ok *)

A: Type
R: A -> A -> Prop
x, y, z: A

rtc R x y -> rtc R y z -> rtc R x z
A: Type
R: A -> A -> Prop
x, y, z: A

rtc R x y -> rtc R y z -> rtc R x z
induction 1; eauto using rtc_once. Defined.
e, e': expr

rtc step e e' -> rtc step (Succ e) (Succ e')
e, e': expr

rtc step e e' -> rtc step (Succ e) (Succ e')
induction 1; eauto using rtc_refl, rtc_once, Step_Succ1. Defined.
e1, e1', e2, e2', e3, e3': expr

rtc step e1 e1' -> rtc step e2 e2' -> rtc step e3 e3' -> rtc step (Rec e1 e2 e3) (Rec e1' e2' e3')
e1, e1', e2, e2', e3, e3': expr

rtc step e1 e1' -> rtc step e2 e2' -> rtc step e3 e3' -> rtc step (Rec e1 e2 e3) (Rec e1' e2' e3')
e2, e2', e3, e3', x: expr

rtc step e2 e2' -> rtc step e3 e3' -> rtc step (Rec x e2 e3) (Rec x e2' e3')
e3, e3', x, x0: expr

rtc step e3 e3' -> rtc step (Rec x x0 e3) (Rec x x0 e3')
x, x0, x1: expr

rtc step (Rec x x0 x1) (Rec x x0 x1)
eapply rtc_refl. Defined.
e1, e1', e2, e2': expr

rtc step e1 e1' -> rtc step e2 e2' -> rtc step (App e1 e2) (App e1' e2')
e1, e1', e2, e2': expr

rtc step e1 e1' -> rtc step e2 e2' -> rtc step (App e1 e2) (App e1' e2')
e2, e2', x: expr

rtc step e2 e2' -> rtc step (App x e2) (App x e2')
x, x0: expr

rtc step (App x x0) (App x x0)
eapply rtc_refl. Defined.
e, e': expr
t: ty

rtc step e e' -> expr_ok e' t -> expr_ok e t
e, e': expr
t: ty

rtc step e e' -> expr_ok e' t -> expr_ok e t
e, e': expr
t: ty
Hstep: rtc step e e'
e'': expr
Hrtc: rtc step e' e''
Hval: value_ok e'' t

expr_ok e t
e, e': expr
t: ty
Hstep: rtc step e e'
e'': expr
Hrtc: rtc step e' e''
Hval: value_ok e'' t

rtc step e e'' /\ value_ok e'' t
split; eauto using rtc_trans. Defined.
v: expr
t: ty

value_ok v t -> value v
v: expr
t: ty

value_ok v t -> value v
v: expr
H: exists n : nat, v = nat_to_expr n

value v
v: expr
t1, t2: ty
H: closed v /\ (exists (x : string) (ebody : expr), v = Lam x ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2))
value v
v: expr
H: exists n : nat, v = nat_to_expr n

value v
n: nat

value (nat_to_expr n)
induction n; simpl; constructor; auto.
v: expr
t1, t2: ty
H: closed v /\ (exists (x : string) (ebody : expr), v = Lam x ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2))

value v
t1, t2: ty
x: string
ebody: expr
Hcloseded: closed (Lam x ebody)
H: forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2

value (Lam x ebody)
constructor. Defined.
v: expr
t: ty

value_ok v t -> expr_ok v t
v: expr
t: ty

value_ok v t -> expr_ok v t
v: expr
t: ty
H: value_ok v t

expr_ok v t
v: expr
t: ty
H: value_ok v t

rtc step v v /\ value_ok v t
v: expr
t: ty
H: value_ok v t

rtc step v v
eapply rtc_refl. Defined.
n: nat

value (nat_to_expr n)
n: nat

value (nat_to_expr n)
induction n; simpl; constructor; auto. Defined.
v1, v2: expr
t1, t2: ty

value_ok v1 (Fun t1 t2) -> value_ok v2 t1 -> expr_ok (App v1 v2) t2
v1, v2: expr
t1, t2: ty

value_ok v1 (Fun t1 t2) -> value_ok v2 t1 -> expr_ok (App v1 v2) t2
v1, v2: expr
t1, t2: ty
Hv1: value_ok v1 (Fun t1 t2)
Hv2: value_ok v2 t1

expr_ok (App v1 v2) t2
v1, v2: expr
t1, t2: ty
Hv1: closed v1 /\ (exists (x : string) (ebody : expr), v1 = Lam x ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2))
Hv2: value_ok v2 t1

expr_ok (App v1 v2) t2
v2: expr
t1, t2: ty
x: string
ebody: expr
Hcloseded: closed (Lam x ebody)
H: forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2
Hv2: value_ok v2 t1

expr_ok (App (Lam x ebody) v2) t2
v2: expr
t1, t2: ty
x: string
ebody: expr
Hcloseded: closed (Lam x ebody)
H: forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2
Hv2: value_ok v2 t1

rtc step (App (Lam x ebody) v2) ?e'
v2: expr
t1, t2: ty
x: string
ebody: expr
Hcloseded: closed (Lam x ebody)
H: forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2
Hv2: value_ok v2 t1
expr_ok ?e' t2
v2: expr
t1, t2: ty
x: string
ebody: expr
Hcloseded: closed (Lam x ebody)
H: forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2
Hv2: value_ok v2 t1

rtc step (App (Lam x ebody) v2) ?e'
eapply rtc_once; [apply Step_AppLam | apply rtc_refl]; eauto using value_ok_value.
v2: expr
t1, t2: ty
x: string
ebody: expr
Hcloseded: closed (Lam x ebody)
H: forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2
Hv2: value_ok v2 t1

expr_ok (subst x v2 ebody) t2
v2: expr
t1, t2: ty
x: string
ebody: expr
Hcloseded: closed (Lam x ebody)
H: forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2
Hv2: value_ok v2 t1

value_ok v2 t1
auto. Defined.
n: nat
v1, v2: expr
t: ty

value_ok v1 t -> value_ok v2 (Fun t t) -> expr_ok (Rec (nat_to_expr n) v1 v2) t
n: nat
v1, v2: expr
t: ty

value_ok v1 t -> value_ok v2 (Fun t t) -> expr_ok (Rec (nat_to_expr n) v1 v2) t
n: nat
v1, v2: expr
t: ty
Hv1: value_ok v1 t
Hv2: value_ok v2 (Fun t t)

expr_ok (Rec (nat_to_expr n) v1 v2) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)

forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
v1: expr
Hv1: value_ok v1 t

expr_ok (Rec Zero v1 v2) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
expr_ok (Rec (Succ (nat_to_expr n)) v1 v2) t
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
v1: expr
Hv1: value_ok v1 t

expr_ok (Rec Zero v1 v2) t
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
v1: expr
Hv1: value_ok v1 t

rtc step (Rec Zero v1 v2) ?e'
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
v1: expr
Hv1: value_ok v1 t
expr_ok ?e' t
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
v1: expr
Hv1: value_ok v1 t

rtc step (Rec Zero v1 v2) ?e'
eapply rtc_once; [apply Step_RecZero | apply rtc_refl]; eauto using value_ok_value.
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
v1: expr
Hv1: value_ok v1 t

expr_ok v1 t
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
v1: expr
Hv1: value_ok v1 t

value_ok v1 t
eauto.
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t

expr_ok (Rec (Succ (nat_to_expr n)) v1 v2) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t

rtc step (Rec (Succ (nat_to_expr n)) v1 v2) ?e'
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
expr_ok ?e' t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t

rtc step (Rec (Succ (nat_to_expr n)) v1 v2) ?e'
eapply rtc_once; [apply Step_RecSucc | apply rtc_refl]; eauto using nat_to_expr_value, value_ok_value.
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t

expr_ok (Rec (nat_to_expr n) (App v2 v1) v2) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t

expr_ok (App v2 v1) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
H: expr_ok (App v2 v1) t
expr_ok (Rec (nat_to_expr n) (App v2 v1) v2) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t

expr_ok (App v2 v1) t
eapply value_ok_App; eauto.
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
H: expr_ok (App v2 v1) t

expr_ok (Rec (nat_to_expr n) (App v2 v1) v2) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
e': expr
Hstep: rtc step (App v2 v1) e'
Hval: value_ok e' t

expr_ok (Rec (nat_to_expr n) (App v2 v1) v2) t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
e': expr
Hstep: rtc step (App v2 v1) e'
Hval: value_ok e' t

rtc step (Rec (nat_to_expr n) (App v2 v1) v2) ?e'
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
e': expr
Hstep: rtc step (App v2 v1) e'
Hval: value_ok e' t
expr_ok ?e' t
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
e': expr
Hstep: rtc step (App v2 v1) e'
Hval: value_ok e' t

rtc step (Rec (nat_to_expr n) (App v2 v1) v2) ?e'
eapply rtc_step_Rec; eauto; eauto using rtc_refl.
n: nat
v2: expr
t: ty
Hv2: value_ok v2 (Fun t t)
IHn: forall v1 : expr, value_ok v1 t -> expr_ok (Rec (nat_to_expr n) v1 v2) t
v1: expr
Hv1: value_ok v1 t
e': expr
Hstep: rtc step (App v2 v1) e'
Hval: value_ok e' t

expr_ok (Rec (nat_to_expr n) e' v2) t
eauto. Defined.
v: expr
t: ty

value_ok v t -> closed v
v: expr
t: ty

value_ok v t -> closed v
v: expr
t: ty
H: value_ok v t

closed v
v: expr
H: exists n : nat, v = nat_to_expr n

closed v
v: expr
t1, t2: ty
H: closed v /\ (exists (x : string) (ebody : expr), v = Lam x ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2))
closed v
v: expr
H: exists n : nat, v = nat_to_expr n

closed v
n: nat

closed (nat_to_expr n)
n: nat
x: string
v: expr

subst x v (nat_to_expr n) = nat_to_expr n
n: nat
x: string
v: expr
IHn: subst x v (nat_to_expr n) = nat_to_expr n

Succ (subst x v (nat_to_expr n)) = Succ (nat_to_expr n)
n: nat
x: string
v: expr
IHn: subst x v (nat_to_expr n) = nat_to_expr n

Succ (nat_to_expr n) = Succ (nat_to_expr n)
auto.
v: expr
t1, t2: ty
H: closed v /\ (exists (x : string) (ebody : expr), v = Lam x ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2))

closed v
v: expr
t1, t2: ty
H: closed v
H0: exists (x : string) (ebody : expr), v = Lam x ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v ebody) e' /\ value_ok e' t2)

closed v
auto. Defined. (* Environments and multi-substitutions *) Definition env := string -> option expr. Fixpoint subst_map (env : env) (e : expr) : expr := match e with | Var x => match env x with | Some v => v | None => e end | Lam x e => Lam x (subst_map (delete x env) e) | App e1 e2 => App (subst_map env e1) (subst_map env e2) | Zero => Zero | Succ e => Succ (subst_map env e) | Rec e1 e2 e3 => Rec (subst_map env e1) (subst_map env e2) (subst_map env e3) end.
env1, env2: string -> option expr
e: expr

env1 == env2 -> subst_map env1 e = subst_map env2 e
env1, env2: string -> option expr
e: expr

env1 == env2 -> subst_map env1 e = subst_map env2 e
e: expr

forall env1 env2 : string -> option expr, env1 == env2 -> subst_map env1 e = subst_map env2 e
x: string
env1, env2: string -> option expr
H: env1 == env2

match env1 x with | Some v => v | None => Var x end = match env2 x with | Some v => v | None => Var x end
x: string
e: expr
IHe: forall env1 env2 : string -> option expr, env1 == env2 -> subst_map env1 e = subst_map env2 e
env1, env2: string -> option expr
H: env1 == env2
subst_map (delete x env1) e = subst_map (delete x env2) e
x: string
env1, env2: string -> option expr
H: env1 == env2

match env1 x with | Some v => v | None => Var x end = match env2 x with | Some v => v | None => Var x end
x: string
env1, env2: string -> option expr
H: env1 == env2

match env2 x with | Some v => v | None => Var x end = match env2 x with | Some v => v | None => Var x end
auto.
x: string
e: expr
IHe: forall env1 env2 : string -> option expr, env1 == env2 -> subst_map env1 e = subst_map env2 e
env1, env2: string -> option expr
H: env1 == env2

subst_map (delete x env1) e = subst_map (delete x env2) e
x: string
e: expr
IHe: forall env1 env2 : string -> option expr, env1 == env2 -> subst_map env1 e = subst_map env2 e
env1, env2: string -> option expr
H: env1 == env2

delete x env1 == delete x env2
simpfun. Defined.
e: expr

subst_map empty e = e
e: expr

subst_map empty e = e
x: string
e: expr
IHe: subst_map empty e = e

Lam x (subst_map (delete x empty) e) = Lam x e
x: string
e: expr
IHe: subst_map empty e = e

subst_map (delete x empty) e = e
x: string
e: expr
IHe: subst_map empty e = e
H: delete x empty == (empty : env)

subst_map (delete x empty) e = e
erewrite subst_map_eq; eauto. Defined.
Gamma: ctx
env: string -> option expr
e: expr
x: string
v: expr
t: ty

typed Gamma e t -> (forall (x : string) (v : expr), env x = Some v -> closed v) -> Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
Gamma: ctx
env: string -> option expr
e: expr
x: string
v: expr
t: ty

typed Gamma e t -> (forall (x : string) (v : expr), env x = Some v -> closed v) -> Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
Gamma: ctx
env: string -> option expr
e: expr
x: string
v: expr
t: ty
H: typed Gamma e t

(forall (x : string) (v : expr), env x = Some v -> closed v) -> Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
Gamma: ctx
e: expr
x: string
v: expr
t: ty
H: typed Gamma e t

forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None

subst x v match env0 x0 with | Some v => v | None => Var x0 end = match env0 x0 with | Some v => v | None => Var x0 end
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (insert x0 t1 Gamma) e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> insert x0 t1 Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
Lam x0 (if string_dec x x0 then subst_map (delete x0 env0) e else subst x v (subst_map (delete x0 env0) e)) = Lam x0 (subst_map (delete x0 env0) e)
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None

subst x v match env0 x0 with | Some v => v | None => Var x0 end = match env0 x0 with | Some v => v | None => Var x0 end
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
e: expr
E: env0 x0 = Some e

subst x v e = e
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
E: env0 x0 = None
subst x v (Var x0) = Var x0
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
e: expr
E: env0 x0 = Some e

subst x v e = e
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
e: expr
E: env0 x0 = Some e

env0 ?x = Some e
eauto.
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
E: env0 x0 = None

subst x v (Var x0) = Var x0
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
E: env0 x0 = None

(if string_dec x x0 then v else Var x0) = Var x0
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x0 = None \/ env0 x0 <> None
E: env0 x0 = None

v = Var x0
destruct H1; simpeq.
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (insert x0 t1 Gamma) e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> insert x0 t1 Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None

Lam x0 (if string_dec x x0 then subst_map (delete x0 env0) e else subst x v (subst_map (delete x0 env0) e)) = Lam x0 (subst_map (delete x0 env0) e)
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (insert x0 t1 Gamma) e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> insert x0 t1 Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
n: x <> x0

Lam x0 (subst x v (subst_map (delete x0 env0) e)) = Lam x0 (subst_map (delete x0 env0) e)
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (insert x0 t1 Gamma) e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> insert x0 t1 Gamma x = None \/ env x <> None -> subst x v (subst_map env e) = subst_map env e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: Gamma x = None \/ env0 x <> None
n: x <> x0

subst x v (subst_map (delete x0 env0) e) = subst_map (delete x0 env0) e
eapply IHtyped; simpfun. Defined.
Gamma: ctx
env: string -> option expr
e: expr
x: string
v: expr
t: ty

typed Gamma e t -> (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (insert x v env) e
Gamma: ctx
env: string -> option expr
e: expr
x: string
v: expr
t: ty

typed Gamma e t -> (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (insert x v env) e
Gamma: ctx
env: string -> option expr
e: expr
x: string
v: expr
t: ty
H: typed Gamma e t

(forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (insert x v env) e
Gamma: ctx
e: expr
x: string
v: expr
t: ty
H: typed Gamma e t

forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (insert x v env) e
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None

subst x v match env0 x0 with | Some v => v | None => Var x0 end = match insert x v env0 x0 with | Some v => v | None => Var x0 end
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (insert x0 t1 Gamma) e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (insert x v env) e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
Lam x0 (if string_dec x x0 then subst_map (delete x0 env0) e else subst x v (subst_map (delete x0 env0) e)) = Lam x0 (subst_map (delete x0 (insert x v env0)) e)
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None

subst x v match env0 x0 with | Some v => v | None => Var x0 end = match insert x v env0 x0 with | Some v => v | None => Var x0 end
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None

subst x v match env0 x0 with | Some v => v | None => Var x0 end = match (if string_dec x x0 then Some v else env0 x0) with | Some v => v | None => Var x0 end
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x0 = None

subst x0 v match env0 x0 with | Some v => v | None => Var x0 end = v
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0
subst x v match env0 x0 with | Some v => v | None => Var x0 end = match env0 x0 with | Some v => v | None => Var x0 end
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x0 = None

subst x0 v match env0 x0 with | Some v => v | None => Var x0 end = v
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x0 = None

subst x0 v (Var x0) = v
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x0 = None

(if string_dec x0 x0 then v else Var x0) = v
destruct string_dec; simpeq.
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0

subst x v match env0 x0 with | Some v => v | None => Var x0 end = match env0 x0 with | Some v => v | None => Var x0 end
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0
e: expr
E: env0 x0 = Some e

subst x v e = e
x: string
v: expr
x0: string
t: ty
Gamma: ctx
H: Gamma x0 = Some t
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0
e: expr
E: env0 x0 = Some e

env0 ?x = Some e
eauto.
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (insert x0 t1 Gamma) e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (insert x v env) e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None

Lam x0 (if string_dec x x0 then subst_map (delete x0 env0) e else subst x v (subst_map (delete x0 env0) e)) = Lam x0 (subst_map (delete x0 (insert x v env0)) e)
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (insert x0 t1 Gamma) e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (insert x v env) e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None

(if string_dec x x0 then subst_map (delete x0 env0) e else subst x v (subst_map (delete x0 env0) e)) = subst_map (delete x0 (insert x v env0)) e
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x0 = None -> subst x0 v (subst_map env e) = subst_map (fun x' : string => if string_dec x0 x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x0 = None

subst_map (fun x' : string => if string_dec x0 x' then None else env0 x') e = subst_map (fun x' : string => if string_dec x0 x' then None else if string_dec x0 x' then Some v else env0 x') e
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0
subst x v (subst_map (fun x' : string => if string_dec x0 x' then None else env0 x') e) = subst_map (fun x' : string => if string_dec x0 x' then None else if string_dec x x' then Some v else env0 x') e
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x0 = None -> subst x0 v (subst_map env e) = subst_map (fun x' : string => if string_dec x0 x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x0 = None

subst_map (fun x' : string => if string_dec x0 x' then None else env0 x') e = subst_map (fun x' : string => if string_dec x0 x' then None else if string_dec x0 x' then Some v else env0 x') e
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x0 = None -> subst x0 v (subst_map env e) = subst_map (fun x' : string => if string_dec x0 x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x0 = None

(fun x' : string => if string_dec x0 x' then None else env0 x') == (fun x' : string => if string_dec x0 x' then None else if string_dec x0 x' then Some v else env0 x')
simpfun.
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0

subst x v (subst_map (fun x' : string => if string_dec x0 x' then None else env0 x') e) = subst_map (fun x' : string => if string_dec x0 x' then None else if string_dec x x' then Some v else env0 x') e
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0

subst_map (fun x' : string => if string_dec x x' then Some v else if string_dec x0 x' then None else env0 x') e = subst_map (fun x' : string => if string_dec x0 x' then None else if string_dec x x' then Some v else env0 x') e
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0
forall (x : string) (v : expr), (if string_dec x0 x then None else env0 x) = Some v -> closed v
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0
(if string_dec x0 x then None else env0 x) = None
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0

subst_map (fun x' : string => if string_dec x x' then Some v else if string_dec x0 x' then None else env0 x') e = subst_map (fun x' : string => if string_dec x0 x' then None else if string_dec x x' then Some v else env0 x') e
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0

(fun x' : string => if string_dec x x' then Some v else if string_dec x0 x' then None else env0 x') == (fun x' : string => if string_dec x0 x' then None else if string_dec x x' then Some v else env0 x')
simpfun.
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0

forall (x : string) (v : expr), (if string_dec x0 x then None else env0 x) = Some v -> closed v
simpfun.
x: string
v: expr
x0: string
e: expr
t1, t2: ty
Gamma: ctx
H: typed (fun x' : string => if string_dec x0 x' then Some t1 else Gamma x') e t2
IHtyped: forall env : string -> option expr, (forall (x : string) (v : expr), env x = Some v -> closed v) -> env x = None -> subst x v (subst_map env e) = subst_map (fun x' : string => if string_dec x x' then Some v else env x') e
env0: string -> option expr
H0: forall (x : string) (v : expr), env0 x = Some v -> closed v
H1: env0 x = None
n: x <> x0

(if string_dec x0 x then None else env0 x) = None
simpfun. Defined. (* Lemmas about environments *) Definition env_ok (env : env) (Gamma : ctx) := forall x, match Gamma x, env x with | Some t, Some v => value_ok v t | None, None => True | _, _ => False end.
x: string
v: expr
t: ty
env: lec12_termination.env
Gamma: ctx

env_ok env Gamma -> value_ok v t -> env_ok (insert x v env) (insert x t Gamma)
x: string
v: expr
t: ty
env: lec12_termination.env
Gamma: ctx

env_ok env Gamma -> value_ok v t -> env_ok (insert x v env) (insert x t Gamma)
x: string
v: expr
t: ty
env: lec12_termination.env
Gamma: ctx
Henv: env_ok env Gamma
Hval: value_ok v t
x': string

match insert x t Gamma x' with | Some t => match insert x v env x' with | Some v => value_ok v t | None => False end | None => match insert x v env x' with | Some _ => False | None => True end end
x: string
v: expr
t: ty
env: lec12_termination.env
Gamma: ctx
Henv: env_ok env Gamma
Hval: value_ok v t
x': string

match (if string_dec x x' then Some t else Gamma x') with | Some t => match (if string_dec x x' then Some v else env x') with | Some v => value_ok v t | None => False end | None => match (if string_dec x x' then Some v else env x') with | Some _ => False | None => True end end
x: string
v: expr
t: ty
env: lec12_termination.env
Gamma: ctx
Henv: env_ok env Gamma
Hval: value_ok v t
x': string
n: x <> x'

match Gamma x' with | Some t => match env x' with | Some v => value_ok v t | None => False end | None => match env x' with | Some _ => False | None => True end end
apply Henv. Defined.
Gamma: ctx
env1, env2: string -> option expr

env2 == env1 -> env_ok env1 Gamma -> env_ok env2 Gamma
Gamma: ctx
env1, env2: string -> option expr

env2 == env1 -> env_ok env1 Gamma -> env_ok env2 Gamma
Gamma: ctx
env1, env2: string -> option expr
H12: env2 == env1
H1: env_ok env1 Gamma
x: string

match Gamma x with | Some t => match env2 x with | Some v => value_ok v t | None => False end | None => match env2 x with | Some _ => False | None => True end end
Gamma: ctx
env1, env2: string -> option expr
H12: forall x : string, env2 x = env1 x
H1: forall x : string, match Gamma x with | Some t => match env1 x with | Some v => value_ok v t | None => False end | None => match env1 x with | Some _ => False | None => True end end
x: string

match Gamma x with | Some t => match env2 x with | Some v => value_ok v t | None => False end | None => match env2 x with | Some _ => False | None => True end end
Gamma: ctx
env1, env2: string -> option expr
H12: forall x : string, env2 x = env1 x
x: string
H1: match Gamma x with | Some t => match env1 x with | Some v => value_ok v t | None => False end | None => match env1 x with | Some _ => False | None => True end end

match Gamma x with | Some t => match env2 x with | Some v => value_ok v t | None => False end | None => match env2 x with | Some _ => False | None => True end end
Gamma: ctx
env1, env2: string -> option expr
H12: forall x : string, env2 x = env1 x
x: string
H1: match Gamma x with | Some t => match env2 x with | Some v => value_ok v t | None => False end | None => match env2 x with | Some _ => False | None => True end end

match Gamma x with | Some t => match env2 x with | Some v => value_ok v t | None => False end | None => match env2 x with | Some _ => False | None => True end end
eauto. Defined.
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty

typed Gamma e t -> env_ok env Gamma -> closed (subst_map env e)
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty

typed Gamma e t -> env_ok env Gamma -> closed (subst_map env e)
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: env_ok env Gamma
x: string
v: expr

subst x v (subst_map env e) = subst_map env e
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: env_ok env Gamma
x: string
v: expr

forall (x : string) (v : expr), env x = Some v -> closed v
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: env_ok env Gamma
x: string
v: expr
Gamma x = None \/ env x <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: env_ok env Gamma
x: string
v: expr

forall (x : string) (v : expr), env x = Some v -> closed v
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: env_ok env Gamma
x: string
v: expr
x0: string
v0: expr
H1: env x0 = Some v0

closed v0
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
x0: string
v0: expr
H1: env x0 = Some v0

closed v0
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
x0: string
H0: match Gamma x0 with | Some t => match env x0 with | Some v => value_ok v t | None => False end | None => match env x0 with | Some _ => False | None => True end end
x: string
v, v0: expr
H1: env x0 = Some v0

closed v0
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
x0: string
v0: expr
H0: match Gamma x0 with | Some t => value_ok v0 t | None => False end
x: string
v: expr
H1: env x0 = Some v0

closed v0
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
x0: string
v0: expr
H0: False
x: string
v: expr
H1: env x0 = Some v0

closed v0
destruct H0.
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: env_ok env Gamma
x: string
v: expr

Gamma x = None \/ env x <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr

Gamma x = None \/ env x <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
t0: ty
E: Gamma x = Some t0

Some t0 = None \/ env x <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
t0: ty
E: Gamma x = Some t0
e0: expr
E': env x = Some e0

Some t0 = None \/ Some e0 <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
t0: ty
E: Gamma x = Some t0
E': env x = None
Some t0 = None \/ None <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
t0: ty
E: Gamma x = Some t0
e0: expr
E': env x = Some e0

Some t0 = None \/ Some e0 <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
t0: ty
E: Gamma x = Some t0
e0: expr
E': env x = Some e0

Some e0 <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
t0: ty
E: Gamma x = Some t0
e0: expr
E': env x = Some e0
H1: Some e0 = None

False
simpeq.
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
H0: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
x: string
v: expr
t0: ty
E: Gamma x = Some t0
E': env x = None

Some t0 = None \/ None <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
x: string
H0: match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
v: expr
t0: ty
E: Gamma x = Some t0
E': env x = None

Some t0 = None \/ None <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
x: string
t0: ty
H0: match env x with | Some v => value_ok v t0 | None => False end
v: expr
E: Gamma x = Some t0
E': env x = None

Some t0 = None \/ None <> None
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
H: typed Gamma e t
x: string
t0: ty
H0: False
v: expr
E: Gamma x = Some t0
E': env x = None

Some t0 = None \/ None <> None
destruct H0. Defined. (* Generalized termination proof *)
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty

typed Gamma e t -> env_ok env Gamma -> expr_ok (subst_map env e) t
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty

typed Gamma e t -> env_ok env Gamma -> expr_ok (subst_map env e) t
Gamma: ctx
env: lec12_termination.env
e: expr
t: ty
Htyped: typed Gamma e t

env_ok env Gamma -> expr_ok (subst_map env e) t
Gamma: ctx
e: expr
t: ty
Htyped: typed Gamma e t

forall env : env, env_ok env Gamma -> expr_ok (subst_map env e) t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (subst_map env (Var x)) t
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
expr_ok (subst_map env (Lam x e)) (Fun t1 t2)
e1, e2: expr
t1, t2: ty
Gamma: ctx
Htyped1: typed Gamma e1 (Fun t1 t2)
Htyped2: typed Gamma e2 t1
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) (Fun t1 t2)
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t1
env: lec12_termination.env
Henv: env_ok env Gamma
expr_ok (subst_map env (App e1 e2)) t2
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma
expr_ok (subst_map env Zero) Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
Henv: env_ok env Gamma
expr_ok (subst_map env (Succ e)) Nat
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma
expr_ok (subst_map env (Rec e1 e2 e3)) t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (subst_map env (Var x)) t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end

expr_ok (subst_map env (Var x)) t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end

expr_ok match env x with | Some v => v | None => Var x end t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end

expr_ok match env x with | Some v => v | None => Var x end t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: match env x with | Some v => value_ok v t | None => False end

expr_ok match env x with | Some v => v | None => Var x end t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
e: expr
Henv: value_ok e t

expr_ok e t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: False
expr_ok (Var x) t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
e: expr
Henv: value_ok e t

expr_ok e t
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
e: expr
Henv: value_ok e t

value_ok e t
auto.
x: string
t: ty
Gamma: ctx
H: Gamma x = Some t
env: lec12_termination.env
Henv: False

expr_ok (Var x) t
destruct Henv.
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (subst_map env (Lam x e)) (Fun t1 t2)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

value_ok (subst_map env (Lam x e)) (Fun t1 t2)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

closed (subst_map env (Lam x e))
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
exists (x0 : string) (ebody : expr), subst_map env (Lam x e) = Lam x0 ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x0 v ebody) e' /\ value_ok e' t2)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

closed (subst_map env (Lam x e))
eapply env_ok_closed; eauto using typed.
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

exists (x0 : string) (ebody : expr), subst_map env (Lam x e) = Lam x0 ebody /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x0 v ebody) e' /\ value_ok e' t2)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

subst_map env (Lam x e) = Lam ?Goal3 ?Goal4 /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst ?Goal3 v ?Goal4) e' /\ value_ok e' t2)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

Lam x (subst_map (delete x env) e) = Lam ?Goal3 ?Goal4 /\ (forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst ?Goal3 v ?Goal4) e' /\ value_ok e' t2)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma

forall v : expr, value_ok v t1 -> exists e' : expr, rtc step (subst x v (subst_map (delete x env) e)) e' /\ value_ok e' t2
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1

exists e' : expr, rtc step (subst x v (subst_map (delete x env) e)) e' /\ value_ok e' t2
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1

exists e' : expr, rtc step (subst_map (insert x v (delete x env)) e) e' /\ value_ok e' t2
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1
forall (x0 : string) (v : expr), delete x env x0 = Some v -> closed v
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1
delete x env x = None
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1

exists e' : expr, rtc step (subst_map (insert x v (delete x env)) e) e' /\ value_ok e' t2
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1

env_ok (insert x v (delete x env)) (insert x t1 Gamma)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1
Hinsert: insert x v (delete x env) == insert x v env

env_ok (insert x v (delete x env)) (insert x t1 Gamma)
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1
Hinsert: insert x v (delete x env) == insert x v env

env_ok (insert x v env) (insert x t1 Gamma)
apply env_ok_insert; auto.
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1

forall (x0 : string) (v : expr), delete x env x0 = Some v -> closed v
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1
x0: string
v0: expr
H: delete x env x0 = Some v0

closed v0
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
v: expr
Hv: value_ok v t1
x0: string
v0: expr
H: delete x env x0 = Some v0

closed v0
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
v: expr
Hv: value_ok v t1
x0: string
v0: expr
H: (if string_dec x x0 then None else env x0) = Some v0

closed v0
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: forall x : string, match Gamma x with | Some t => match env x with | Some v => value_ok v t | None => False end | None => match env x with | Some _ => False | None => True end end
v: expr
Hv: value_ok v t1
x0: string
v0: expr
n: x <> x0
H: env x0 = Some v0

closed v0
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
x0: string
Henv: match Gamma x0 with | Some t => match env x0 with | Some v => value_ok v t | None => False end | None => match env x0 with | Some _ => False | None => True end end
v: expr
Hv: value_ok v t1
v0: expr
n: x <> x0
H: env x0 = Some v0

closed v0
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
x0: string
v0: expr
Henv: match Gamma x0 with | Some t => value_ok v0 t | None => False end
v: expr
Hv: value_ok v t1
n: x <> x0
H: env x0 = Some v0

closed v0
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
x0: string
v0: expr
t: ty
Henv: value_ok v0 t
v: expr
Hv: value_ok v t1
n: x <> x0
H: env x0 = Some v0

closed v0
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
x0: string
v0: expr
t: ty
Henv: value_ok v0 t
v: expr
Hv: value_ok v t1
n: x <> x0
H: env x0 = Some v0

value_ok v0 ?t
eauto.
x: string
e: expr
t1, t2: ty
Gamma: ctx
Htyped: typed (insert x t1 Gamma) e t2
IHHtyped: forall env : lec12_termination.env, env_ok env (insert x t1 Gamma) -> expr_ok (subst_map env e) t2
env: lec12_termination.env
Henv: env_ok env Gamma
v: expr
Hv: value_ok v t1

delete x env x = None
simpfun.
e1, e2: expr
t1, t2: ty
Gamma: ctx
Htyped1: typed Gamma e1 (Fun t1 t2)
Htyped2: typed Gamma e2 t1
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) (Fun t1 t2)
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t1
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (subst_map env (App e1 e2)) t2
e1, e2: expr
t1, t2: ty
Gamma: ctx
Htyped1: typed Gamma e1 (Fun t1 t2)
Htyped2: typed Gamma e2 t1
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) (Fun t1 t2)
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t1
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (App (subst_map env e1) (subst_map env e2)) t2
e1, e2: expr
t1, t2: ty
Gamma: ctx
Htyped1: typed Gamma e1 (Fun t1 t2)
Htyped2: typed Gamma e2 t1
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) (Fun t1 t2)
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t1
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: value_ok v1 (Fun t1 t2)

expr_ok (App (subst_map env e1) (subst_map env e2)) t2
e1, e2: expr
t1, t2: ty
Gamma: ctx
Htyped1: typed Gamma e1 (Fun t1 t2)
Htyped2: typed Gamma e2 t1
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) (Fun t1 t2)
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t1
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: value_ok v1 (Fun t1 t2)
v2: expr
Hstep2: rtc step (subst_map env e2) v2
Hval2: value_ok v2 t1

expr_ok (App (subst_map env e1) (subst_map env e2)) t2
e1, e2: expr
t1, t2: ty
Gamma: ctx
Htyped1: typed Gamma e1 (Fun t1 t2)
Htyped2: typed Gamma e2 t1
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) (Fun t1 t2)
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t1
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: value_ok v1 (Fun t1 t2)
v2: expr
Hstep2: rtc step (subst_map env e2) v2
Hval2: value_ok v2 t1

expr_ok (App v1 v2) t2
eapply value_ok_App; eauto.
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (subst_map env Zero) Nat
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok Zero Nat
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

rtc step Zero ?e' /\ value_ok ?e' Nat
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

rtc step Zero ?e'
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma
value_ok ?e' Nat
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

rtc step Zero ?e'
apply rtc_refl.
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

value_ok Zero Nat
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

exists n : nat, Zero = nat_to_expr n
Gamma: ctx
env: lec12_termination.env
Henv: env_ok env Gamma

Zero = nat_to_expr 0
auto.
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (subst_map env (Succ e)) Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (Succ (subst_map env e)) Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
Henv: expr_ok (subst_map env e) Nat

expr_ok (Succ (subst_map env e)) Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
e': expr
Hstep: rtc step (subst_map env e) e'
Hval: value_ok e' Nat

expr_ok (Succ (subst_map env e)) Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
e': expr
Hstep: rtc step (subst_map env e) e'
Hval: value_ok e' Nat

rtc step (Succ (subst_map env e)) (Succ e') /\ value_ok (Succ e') Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
e': expr
Hstep: rtc step (subst_map env e) e'
Hval: value_ok e' Nat

rtc step (Succ (subst_map env e)) (Succ e')
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
e': expr
Hstep: rtc step (subst_map env e) e'
Hval: value_ok e' Nat
value_ok (Succ e') Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
e': expr
Hstep: rtc step (subst_map env e) e'
Hval: value_ok e' Nat

rtc step (Succ (subst_map env e)) (Succ e')
eauto using rtc_step_Succ.
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
e': expr
Hstep: rtc step (subst_map env e) e'
Hval: value_ok e' Nat

value_ok (Succ e') Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
e': expr
Hstep: rtc step (subst_map env e) e'
Hval: exists n : nat, e' = nat_to_expr n

value_ok (Succ e') Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
n: nat
Hstep: rtc step (subst_map env e) (nat_to_expr n)

value_ok (Succ (nat_to_expr n)) Nat
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
n: nat
Hstep: rtc step (subst_map env e) (nat_to_expr n)

exists n0 : nat, Succ (nat_to_expr n) = nat_to_expr n0
e: expr
Gamma: ctx
Htyped: typed Gamma e Nat
IHHtyped: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e) Nat
env: lec12_termination.env
n: nat
Hstep: rtc step (subst_map env e) (nat_to_expr n)

Succ (nat_to_expr n) = nat_to_expr (S n)
auto.
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma

expr_ok (subst_map env (Rec e1 e2 e3)) t
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: value_ok v1 Nat

expr_ok (subst_map env (Rec e1 e2 e3)) t
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: value_ok v1 Nat
v2: expr
Hstep2: rtc step (subst_map env e2) v2
Hval2: value_ok v2 t

expr_ok (subst_map env (Rec e1 e2 e3)) t
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: value_ok v1 Nat
v2: expr
Hstep2: rtc step (subst_map env e2) v2
Hval2: value_ok v2 t
v3: expr
Hstep3: rtc step (subst_map env e3) v3
Hval3: value_ok v3 (Fun t t)

expr_ok (subst_map env (Rec e1 e2 e3)) t
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: value_ok v1 Nat
v2: expr
Hstep2: rtc step (subst_map env e2) v2
Hval2: value_ok v2 t
v3: expr
Hstep3: rtc step (subst_map env e3) v3
Hval3: value_ok v3 (Fun t t)

expr_ok (Rec v1 v2 v3) t
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma
v1: expr
Hstep1: rtc step (subst_map env e1) v1
Hval1: exists n : nat, v1 = nat_to_expr n
v2: expr
Hstep2: rtc step (subst_map env e2) v2
Hval2: value_ok v2 t
v3: expr
Hstep3: rtc step (subst_map env e3) v3
Hval3: value_ok v3 (Fun t t)

expr_ok (Rec v1 v2 v3) t
e1, e2, e3: expr
Gamma: ctx
t: ty
Htyped1: typed Gamma e1 Nat
Htyped2: typed Gamma e2 t
Htyped3: typed Gamma e3 (Fun t t)
IHHtyped1: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e1) Nat
IHHtyped2: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e2) t
IHHtyped3: forall env : lec12_termination.env, env_ok env Gamma -> expr_ok (subst_map env e3) (Fun t t)
env: lec12_termination.env
Henv: env_ok env Gamma
n1: nat
Hstep1: rtc step (subst_map env e1) (nat_to_expr n1)
v2: expr
Hstep2: rtc step (subst_map env e2) v2
Hval2: value_ok v2 t
v3: expr
Hstep3: rtc step (subst_map env e3) v3
Hval3: value_ok v3 (Fun t t)

expr_ok (Rec (nat_to_expr n1) v2 v3) t
eapply expr_ok_rec; eauto. Defined. (* Final theorem *)
e: expr
t: ty

typed empty e t -> terminates e
e: expr
t: ty

typed empty e t -> terminates e
e: expr
t: ty
Htyped: typed empty e t

terminates e
e: expr
t: ty
Htyped: expr_ok (subst_map empty e) t

terminates e
e: expr
t: ty
Htyped: typed empty e t
env_ok empty empty
e: expr
t: ty
Htyped: expr_ok (subst_map empty e) t

terminates e
e: expr
t: ty
Htyped: expr_ok e t

terminates e
e: expr
t: ty
e': expr
Hstep: rtc step e e'
Hval: value_ok e' t

terminates e
e: expr
t: ty
e': expr
Hstep: rtc step e e'
Hval: value_ok e' t

rtc step e e' /\ value e'
e: expr
t: ty
e': expr
Hstep: rtc step e e'
Hval: value_ok e' t

value e'
e: expr
t: ty
e': expr
Hstep: rtc step e e'
Hval: value_ok e' t

value_ok e' ?t
eauto.
e: expr
t: ty
Htyped: typed empty e t

env_ok empty empty
constructor. Defined. (* Definition ack m := rec m S (fun f => fun n => rec (S n) 1 f). *) Definition Ack := Lam "m" (Rec (Var "m") (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f"))))).

typed empty Ack (Fun Nat (Fun Nat Nat))

typed empty Ack (Fun Nat (Fun Nat Nat))
eauto 20 using typed. Defined. Definition ACK n m := App (App Ack (nat_to_expr n)) (nat_to_expr m).
n: nat

typed empty (nat_to_expr n) Nat
n: nat

typed empty (nat_to_expr n) Nat
induction n; simpl; eauto using typed. Defined.
n, m: nat

typed empty (ACK n m) Nat
n, m: nat

typed empty (ACK n m) Nat
n, m: nat

typed empty (App (App Ack (nat_to_expr n)) (nat_to_expr m)) Nat
eauto 20 using typed, Ack_typed, nat_to_expr_typed. Defined.
= ex_intro (fun e' : expr => rtc step (ACK 0 0) e' /\ value e') (Succ Zero) (conj (rtc_once step (App (App (Lam "m" (Rec (Var "m") (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f")))))) Zero) Zero) (App (Rec Zero (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f"))))) Zero) (Succ Zero) (Step_App1 (App (Lam "m" (Rec (Var "m") (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f")))))) Zero) (Rec Zero (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f"))))) Zero (Step_AppLam "m" Zero (Rec (Var "m") (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f"))))) Val_Zero)) (rtc_once step (App (Rec Zero (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f"))))) Zero) (App (Lam "x" (Succ (Var "x"))) Zero) (Succ Zero) (Step_App1 (Rec Zero (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f"))))) (Lam "x" (Succ (Var "x"))) Zero (Step_RecZero (Lam "x" (Succ (Var "x"))) (Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f")))) (Val_Lam "x" (Succ (Var "x"))) (Val_Lam "f" (Lam "n" (Rec (Succ (Var "n")) (Succ Zero) (Var "f")))))) (rtc_once step (App (Lam "x" (Succ (Var "x"))) Zero) (Succ Zero) (Succ Zero) (Step_AppLam "x" Zero (Succ (Var "x")) Val_Zero) (rtc_refl step (Succ Zero))))) (Val_Succ Zero Val_Zero)) : terminates (ACK 0 0)