mpri-funcprog-project/coq/LambdaCalculusValues.v
2017-09-28 10:36:07 +02:00

180 lines
3.9 KiB
Coq

Require Import MyTactics.
Require Import LambdaCalculusSyntax.
(* The syntactic subcategory of values is decidable. *)
Definition if_value {A} (t : term) (a1 a2 : A) : A :=
match t with
| Var _ | Lam _ => a1
| _ => a2
end.
Definition is_value (t : term) :=
if_value t True False.
Hint Extern 1 (is_value _) => (simpl; tauto) : is_value obvious.
(* A term either is or is not a value. *)
Lemma value_or_nonvalue:
forall t,
is_value t \/ ~ is_value t.
Proof.
destruct t; simpl; eauto.
Qed.
(* Simplification rules for [if_value]. *)
Lemma if_value_value:
forall A v (a1 a2 : A),
is_value v ->
if_value v a1 a2 = a1.
Proof.
destruct v; simpl; tauto.
Qed.
Lemma if_value_nonvalue:
forall A t (a1 a2 : A),
~ is_value t ->
if_value t a1 a2 = a2.
Proof.
destruct t; simpl; tauto.
Qed.
(* The syntactic subcategory of values is preserved by renamings. *)
Lemma is_value_renaming:
forall v xi,
is_value v ->
is_value v.[ren xi].
Proof.
destruct v; simpl; eauto.
Qed.
Lemma is_nonvalue_renaming:
forall v xi,
~ is_value v ->
~ is_value v.[ren xi].
Proof.
destruct v; simpl; eauto.
Qed.
Hint Resolve is_value_renaming is_nonvalue_renaming : is_value obvious.
Ltac is_value :=
eauto with is_value.
(* The tactic [not_a_value] can be used to prove that the current case
is impossible, because we have a hypothesis of the form [~ is_value v],
where [v] clearly is a value. *)
Ltac not_a_value :=
solve [ false; is_value ].
Ltac if_value :=
repeat first [ rewrite if_value_value by is_value |
rewrite if_value_nonvalue by is_value ].
(* The tactic [value_or_nonvalue t] creates two cases: either [t] is a value,
or it isn't. *)
Ltac value_or_nonvalue t :=
destruct (value_or_nonvalue t);
if_value.
(* The tactic [value_or_app_or_let] creates three cases: either [t] is a value,
or it is an application, or it is a [let] construct. *)
Ltac value_or_app_or_let t :=
value_or_nonvalue t; [|
destruct t as [ ? | ? | t1 t2 | t1 t2 ]; [ not_a_value | not_a_value | |]
(* In principle, we should not fix the names [t1] and [t2] here,
as it might cause name clashes. *)
].
(* The predicate [is_value_subst sigma] holds if every term in the
codomain of the substitution [sigma] is a value. *)
Definition is_value_subst (sigma : var -> term) :=
forall x, is_value (sigma x).
Lemma is_value_subst_ids:
is_value_subst ids.
Proof.
intros x. is_value.
Qed.
Lemma is_value_subst_cons:
forall v sigma,
is_value v ->
is_value_subst sigma ->
is_value_subst (v .: sigma).
Proof.
intros. intros [|x]; is_value.
Qed.
Definition is_value_subst_up:
forall sigma,
is_value_subst sigma ->
is_value_subst (up sigma).
Proof.
intros sigma h. intros [|x]; asimpl.
{ simpl. eauto. }
{ is_value. }
Qed.
Definition is_value_subst_upn:
forall sigma i,
is_value_subst sigma ->
is_value_subst (upn i sigma).
Proof.
induction i; intros; asimpl.
{ eauto. }
{ rewrite <- fold_up_upn. eauto using is_value_subst_up. }
Qed.
Lemma is_value_subst_renaming:
forall sigma i,
is_value_subst sigma ->
is_value_subst (sigma >> ren (+i)).
Proof.
intros. intro x. asimpl. is_value.
Qed.
Hint Resolve is_value_subst_up is_value_subst_upn is_value_subst_renaming
: is_value obvious.
Lemma values_are_preserved_by_value_substitutions:
forall v sigma,
is_value v ->
is_value_subst sigma ->
is_value v.[sigma].
Proof.
destruct v; simpl; intros; eauto with is_value.
Qed.
Lemma nonvalues_are_preserved_by_substitutions:
forall t sigma,
~ is_value t ->
~ is_value t.[sigma].
Proof.
destruct t; simpl; tauto.
Qed.
Hint Resolve
is_value_subst_ids
is_value_subst_cons
values_are_preserved_by_value_substitutions
nonvalues_are_preserved_by_substitutions
: is_value obvious.
Lemma is_ren_is_value_subst:
forall sigma,
is_ren sigma ->
is_value_subst sigma.
Proof.
intros ? [ xi ? ]. subst. eauto with is_value.
Qed.
Hint Resolve is_ren_is_value_subst : is_value obvious.