Coq 简单型lambda演算中闭项自由变量的归纳假设

Coq 简单型lambda演算中闭项自由变量的归纳假设,coq,lambda-calculus,induction,Coq,Lambda Calculus,Induction,我试图在Coq中形式化简单类型的lambda演算,但在陈述一个引理时遇到了一个问题,即空上下文中类型良好的表达式的自由变量集是空的 以下是五月正式化的相关部分 Require Import Coq.Arith.Arith. Require Import Coq.MSets.MSets. Require Import Coq.FSets.FMaps. Inductive type : Set := | tunit : type | tfun : type -> type -> typ

我试图在Coq中形式化简单类型的lambda演算,但在陈述一个引理时遇到了一个问题,即空上下文中类型良好的表达式的自由变量集是空的

以下是五月正式化的相关部分

Require Import Coq.Arith.Arith.
Require Import Coq.MSets.MSets.
Require Import Coq.FSets.FMaps.

Inductive type : Set :=
| tunit : type
| tfun : type -> type -> type.

Module Var := Nat.
Definition var : Set := Var.t.
Module VarSet := MSetAVL.Make Var.
Module VarSetFacts := MSetFacts.Facts VarSet.
Module VarSetProps := MSetProperties.Properties VarSet.
Module Context := FMapWeakList.Make Var.
Module ContextFacts := FMapFacts.Facts Context.
Module ContextProps := FMapFacts.Properties Context.
Definition context := Context.t type.
Definition context_empty : context := Context.empty type.

Inductive expr : Set :=
| eunit : expr
| evar : var -> expr
| eabs : var -> type -> expr -> expr
| eapp : expr -> expr -> expr.

Fixpoint free_vars (e : expr) : VarSet.t :=
  match e with
  | eunit => VarSet.empty
  | evar y => VarSet.singleton y
  | eabs y _ e => VarSet.remove y (free_vars e)
  | eapp e1 e2 => VarSet.union (free_vars e1) (free_vars e2)
  end.

Inductive has_type : context -> expr -> type -> Prop :=
| has_type_unit : forall c,
    has_type c eunit tunit

| has_type_var : forall c x t,
    Context.find x c = Some t ->
    has_type c (evar x) t

| has_type_abs : forall c x t1 t2 e,
    has_type (Context.add x t1 c) e t2 ->
    has_type c (eabs x t1 e) (tfun t1 t2)

| has_type_app : forall c e1 e2 t1 t2,
    has_type c e1 (tfun t1 t2) ->
    has_type c e2 t1 ->
    has_type c (eapp e1 e2) t2.

Check has_type_ind.

Lemma has_type_empty_context_free_vars : forall e t,
  has_type context_empty e t ->
  VarSet.Empty (free_vars e).
Proof.
  intros e t H.
  remember context_empty as c.
  induction H; subst.
  - apply VarSet.empty_spec.
  - rewrite ContextFacts.empty_o in H.
    congruence.
  - simpl.
    admit. (* Wrong induction hypothesis *)
  - simpl.
    rewrite VarSetProps.empty_union_1; auto.
Admitted.
问题似乎在于我的归纳假设是错误的。它只是说

Context.add x t1 context_empty = context_empty ->
  VarSet.Empty (free_vars e)
这是非常正确的,因为假设是错误的。我尝试对表达式进行归纳,并重新表述定理,以获得正确的归纳假设,但无法理解它

定义和证明此属性的正确方法是什么

解决方案 在Yves之后,感谢ejgallego的评论,我首先证明了一个广义引理

Lemma has_type_free_vars_in_context : forall c e t,
  has_type c e t ->
  VarSet.For_all (fun x => Context.mem x c = true) (free_vars e).
Proof.
  intros c e t H.
  induction H; simpl.
  - intros x contra.
    apply VarSetFacts.empty_iff in contra.
    inversion contra.
  - intros y H2.
    apply Context.mem_1.
    apply ContextFacts.in_find_iff.
    apply VarSet.singleton_spec in H2.
    subst.
    rewrite H.
    discriminate.
  - intros y H2.
    unfold VarSet.For_all in *.
    apply VarSet.remove_spec in H2 as [H2 H3].
    specialize (IHhas_type y H2).
    rewrite ContextFacts.add_neq_b in IHhas_type; auto.
  - intros x H2.
    apply VarSet.union_spec in H2 as [H2 | H2]; auto.
Qed.
用来证明我的定理

Lemma has_type_empty_context_free_vars : forall e t,
  has_type context_empty e t ->
  VarSet.Empty (free_vars e).
Proof.
  intros e t H.
  apply has_type_free_vars_in_context in H.
  induction (free_vars e) using VarSetProps.set_induction.
  - assumption.
  - rename t0_1 into s.
    rename t0_2 into s'.
    apply VarSetProps.Add_Equal in H1.
    unfold VarSet.For_all in *.
    specialize (H x).
    rewrite H1 in H.
    specialize (H (VarSetFacts.add_1 s eq_refl)).
    Search (Context.empty).
    rewrite ContextFacts.empty_a in H.
    discriminate.
Qed.

它现在起作用了。非常感谢你。是否有方法重构此解决方案以实现更高的自动化程度、更好的可读性、更好的维护等?

您对语句“has_type…”的假设进行归纳是正确的,但您可能需要加载归纳。换句话说,您需要证明一个更强的语句,使环境成为变量,并表示
e
中的自由变量集必须位于上下文中具有类型的变量内。

谢谢您的提示。我用我的新尝试编辑了这个问题。这似乎有道理,但这是我第一次尝试使用[VarSet.for_all](还有[fmap]和[MSet],我尝试将STLC形式化,部分是为了了解它们),我不知道如何继续。
Search u VarSet.for_all.
会给你一些帮助,无论如何,定义是可以直接使用的,因为它只是一个普通引理:
对于所有的ps:=forall x:elt,x\in s->px.
所以如果你有
x
的成员资格证明,你可以直接导出
px
。谢谢,它现在可以工作了。你对改进证据有什么建议吗?