我试图证明Coq中的归纳原理。由于数据结构的定义,必须通过两个嵌套导入来显示该原理。外部归纳是通过Fixpoint
构造完成的,内部归纳是通过原则list_ind
完成的。
现在出现的问题是内部归纳的归纳论证是函数的结果,即dfs t
。
Inductive SearchTree (A : Type) : Type :=
| empty : SearchTree A
| leaf : A -> SearchTree A
| choice : SearchTree A -> SearchTree A -> SearchTree A.
Fixpoint dfs (A : Type) (t: SearchTree A) : list A :=
match t with
| empty => nil
| leaf x => cons x nil
| choice t1 t2 => app (dfs t1) (dfs t2)
end.
在内部诱导步骤中,我需要能够将外部诱导假设应用于dfs t
的第一个元素。但是:在dfs t
上进行归纳时,这是不可能的,因为它会导致不正确的递归。
在我看来,“正常”方法是对t
进行归纳和简化,但是如果t = choice t1 t2
这总是导致最初的问题,因为dfs (choice t1 t2)
只会减少到dfs t1 ++ dfs t2
。
有人建议如何继续这个证明吗?
编辑:认为显示代码可能有点多,但现在是:
Require Import Setoid.
Require Import Coq.Lists.List.
Set Implicit Arguments.
Set Contextual Implicit.
Section list.
Section listEquality.
Variable A : Type.
Variable eqA : A -> A -> Prop.
Inductive EqL : list A -> list A -> Prop :=
| EqL_nil : EqL nil nil
| EqL_cons : forall (x y : A) (xs ys : list A),
eqA x y ->
EqL xs ys ->
EqL (cons x xs) (cons y ys).
End listEquality.
End list.
Section SearchTree.
Inductive SearchTree (A : Type) : Type :=
| empty : SearchTree A
| leaf : A -> SearchTree A
| choice : SearchTree A -> SearchTree A -> SearchTree A.
Fixpoint dfs (A : Type) (t: SearchTree A) : list A :=
match t with
| empty => nil
| leaf x => cons x nil
| choice t1 t2 => app (dfs t1) (dfs t2)
end.
Section DFSEquality.
Variable A : Type.
Variable eqA : relation A.
Definition EqDFS (t1 t2: SearchTree A) : Prop :=
EqL eqA (dfs t1) (dfs t2).
End DFSEquality.
End SearchTree.
Section List.
Inductive List A :=
| Nil : List A
| Cons : SearchTree A -> SearchTree (List A) -> List A.
End List.
Section EqND.
Variable A : Type.
Variable eqA : relation A.
Inductive EqND : List A -> List A -> Prop :=
| Eq_Nil : EqND Nil Nil
| Eq_Cons : forall tx ty txs tys,
EqDFS eqA tx ty ->
EqDFS EqND txs tys ->
EqND (Cons tx txs) (Cons ty tys).
End EqND.
Section EqNDInd.
Variable A : Type.
Variable eqA : relation A.
Variable P : List A -> List A -> Prop.
Hypothesis BC : P Nil Nil.
Hypothesis ST: forall mx my mxs mys,
EqDFS eqA mx my
-> EqDFS (fun xs ys => EqND eqA xs ys /\ P xs ys) mxs mys
-> P (Cons mx mxs) (Cons my mys).
Fixpoint IND (xs ys : List A) { struct xs } : EqND eqA xs ys -> P xs ys.
Proof.
intro eq.
destruct xs,ys.
+ exact BC.
+ inversion eq.
+ inversion eq.
+ inversion eq. subst. apply ST.
++ exact H2.
++ unfold EqDFS in *.
generalize dependent (dfs s2).
induction (dfs s0).
+++ intros. inversion H4. constructor.
+++ intros. inversion H4. subst. constructor.
++++ split.
* exact H1.
* apply IND. exact H1. (* Guarded. *)
++++ clear IND. firstorder.
Admitted.
End EqNDInd.
问题发生在证明IND
,Guarded.
注释失败。
答案 0 :(得分:2)
要使用嵌套递归,您必须使用"修复1"来使用原始修复构造。例如战术。归纳原则不会给你正确的递归调用。请注意,反转可能会进行重写,使警卫检查员感到困惑。
实际上,如果你想要"嵌套" fixpoint不是在原始列表的子项上,而是在[dfs t]上,那么它不再是结构递归,你需要使用有根据的递归来证明递归。我在玫瑰树上有一个类似的example,其中使用了有根据的嵌套递归。
答案 1 :(得分:2)
您的尝试有两个问题:
您编写IND
的方式会阻止递归参数为eq: EqND eqA xs ys
,而这将是自然的。
正如@Matthieu Sozeau所说,多次反转会引入噪音。
令人惊讶的是,证据很短。
这是我的解决方案:
Fixpoint IND (xs ys : List A) (eq: EqND eqA xs ys) : P xs ys.
Proof.
destruct eq.
- assumption.
- apply ST.
+ assumption.
+ unfold EqDFS in H0 |- *. induction H0.
* constructor.
* constructor.
-- split.
++ assumption.
++ apply IND. assumption.
-- assumption.
Qed.