%% Lambda calculus and various results on typing and evaluation
%%
%% Even though we use higher-order abstract syntax here, we do not need
%% to define a meta-level context predicate because all contexts are
%% empty in the inductions.

Specification "eval".

%%
%% Determinancy
%%

Theorem eval_det :
  forall E V1 V2, {eval E V1} -> {eval E V2} -> V1 = V2.
induction on 1. intros. case H1.
  case H2. search.
  case H2. apply IH to H3 H5. apply IH to H4 H6. search.

Theorem step_det :
  forall E1 E2 E3, {step E1 E2} -> {step E1 E3} -> E2 = E3.
induction on 1. intros. case H1.
  case H2.
    search.
    case H3.
  case H2.
    case H3.
    apply IH to H3 H4. search.

Theorem nstep_det :
  forall E R1 R2, {nstep E (abs R1)} -> {nstep E (abs R2)} -> R1 = R2.
induction on 1. intros. case H1.
  case H2.
    search.
    case H3.
  case H2.
    case H3.
    apply step_det to H3 H5. apply IH to H4 H6. search.

%%
%% Equivalence of semantics
%%

Theorem nstep_lemma :
  forall M N R V, {nstep M (abs R)} -> {nstep (R N) V} -> {nstep (app M N) V}.
induction on 1. intros. case H1.
  search.
  apply IH to H4 H2. search.

Theorem eval_nstep :
  forall E V, {eval E V} -> {nstep E V}.
induction on 1. intros. case H1.
  search.
  apply IH to H2. apply IH to H3. apply nstep_lemma to H4 H5. search.

Theorem step_eval_lemma :
  forall A B C, {step A B} -> {eval B C} -> {eval A C}.
induction on 1. intros. case H1.
  search.
  case H2. apply IH to H3 H4. search.

Theorem nstep_eval :
  forall E R, {nstep E (abs R)} -> {eval E (abs R)}.
induction on 1. intros. case H1.
  search.
  apply IH to H3. apply step_eval_lemma to H2 H4. search.


%%
%% Subject reduction
%%

Theorem sr_eval :
  forall E V T, {eval E V} -> {of E T} -> {of V T}.
induction on 1. intros. case H1.
  search.
  case H2. apply IH to H3 H5. case H7. inst H8 with n1 = N.
    cut H9 with H6. apply IH to H4 H10. search.

Theorem sr_step :
  forall E1 E2 T, {step E1 E2} -> {of E1 T} -> {of E2 T}.
induction on 1. intros. case H1.
  case H2. case H3.
    inst H5 with n1 = M. cut H6 with H4.
      search.
  case H2.
    apply IH to H3 H4. search.

Theorem sr_nstep :
  forall E1 E2 T, {nstep E1 E2} -> {of E1 T} -> {of E2 T}.
induction on 1. intros. case H1.
  search.
  apply sr_step to H3 H2.
    apply IH to H4 H5. search.


%%
%% Misc
%%

% A cut property for typing judgments
Theorem type_subst : forall L E E' T T', nabla x,
  {L, of x T' |- of (E x) T} -> {L |- of E' T'} ->
    {L |- of (E E') T}.
intros.
inst H1 with n1 = E'.
cut H3 with H2.
search.

% Self application cannot be simply-typed
Theorem of_self_app_absurd : forall T,
  {of (abs (x\ app x x)) T} -> false.
intros. case H1. case H2.
  case H3. case H6. 
    case H5. case H4. case H8. 
      case H7.
      case H9.
    case H7.
  case H4. case H3. case H5.

% The term (lambda x . x x) (lambda x . x x) does not evaluate to a value
Theorem no_eval : forall V,
  {eval (app (abs x\ app x x) (abs x\ app x x)) V} -> false.
induction on 1. intros. case H1.
  case H2. apply IH to H3.

% We can also define divergence coinductivly to prove that
% (lambda x . x x) (lambda x . x x) diverges

CoDefine diverge : tm -> prop by
  diverge (app M N) := diverge M ;
  diverge (app M N) := exists R, {eval M (abs R)} /\ diverge (R N).

Theorem omega_diverge :
  diverge (app (abs x\ app x x) (abs x\ app x x)).
coinduction. search.

% More generally we can prove that evaluation and divergence are
% mutually exclusive
Theorem eval_diverge_absurd : forall M V,
  {eval M V} -> diverge M -> false.
induction on 1. intros. case H1.
  case H2.
  case H2.
    apply IH to H3 H5.
    apply eval_det to H3 H5. apply IH to H4 H6.
