Inductive subseq : list nat -> list nat -> Prop :=
| subseq_base : subseq [] []
| subseq_there : forall seq l x, subseq seq l -> subseq seq (x :: l)
| subseq_here : forall seq l x, subseq seq l -> subseq (x :: seq) (x :: l).
Theorem subseq_snd :
forall l1 l2 l,
subseq (l1 ++ l2) l -> subseq l1 l.
Proof.
intros.
induction H.
-
1 subgoal
l1, l2 : list nat
______________________________________(1/1)
subseq l1 [ ]
基本上,Coq在这种情况下无法识别l1 ++ l2 = []
也意味着l1 = []
,但是由于没有前提,我也不能证明这一点。在这里应该做什么?
答案 0 :(得分:2)
您需要对l1
和l
进行归纳,并使用H
来消除不可能的情况。基本上,我认为您不能直接对H
进行归纳;您必须对其相关的值进行归纳,并在遍历它们时将H
撕毁。
这个引理应该首先定义。您可以可以在证明中内联它,但是它的类型很有趣,可以单独使用:
Theorem subseq_nil (l : list nat): subseq nil l.
Proof.
induction l; constructor; assumption.
Qed.
然后是主要证明:
Theorem subseq_snd (l1 l2 l : list nat): subseq (l1 ++ l2) l -> subseq l1 l.
Proof.
(* I like to give parameters on the left side of the :, so I use revert to get the
correct goal for the induction:
forall l, subseq (l1 ++ l2) l -> subseq l1 l *)
revert l; induction l1 as [ | x l1 Hl1]; intro l. (* It's best to give names *)
- intros ?.
apply subseq_nil.
(* Below we get H : subseq (x :: foo) bar. The inversion tactic is like destruct
but it spews out equalities about the type indices instead of leaving you stranded
like induction would. In the l=nil case, inversion produces a contradiction,
because subseq_nil has been ruled out, and, in the l=cons case, it case splits
between subseq_there and subseq_here. *)
- induction l as [ | x' l Hl]; simpl; intro H; inversion H.
+ apply subseq_there.
apply Hl.
assumption.
+ apply subseq_here.
apply Hl1.
assumption.
Qed.
答案 1 :(得分:2)
我无法使用remember
来回答这个问题。该证明看起来非常类似于@HTNW提供的证明,但不使用dependent induction
也不执行嵌套归纳。
Theorem subseq_snd :
forall l1 l2 l,
subseq (l1 ++ l2) l -> subseq l1 l.
Proof.
intros. remember (l1++l2) as L.
revert l1 l2 HeqL.
induction H; intros.
- destruct l1.
+ apply subseq_base.
+ discriminate.
- apply subseq_there. eapply IHsubseq, HeqL.
- destruct l1.
+ apply subseq_nil.
+ inversion HeqL; subst. apply subseq_here.
eapply IHsubseq; reflexivity.
Qed.
答案 2 :(得分:1)
您可以使用实验性策略dependent induction
。这可能是最接近您想要的。您将需要此引理:
Theorem subseq_nil (l : list nat): subseq nil l.
Proof.
induction l; constructor; assumption.
Qed.
与induction
+ inversion
的两倍相比,即使更长,也更容易阅读。它有3个-
项目符号,每个构造函数一个,只有一个递归入口点。确实,直到我使用subseq
之前,我什至没有意识到dependent induction
代表不连续的子序列,这使程序的结构清晰到足以让我意识到正在发生的事情。而且,产生的程序项要小得多。
Theorem subseq_app (l1 l2 l : list nat): subseq (l1 ++ l2) l -> subseq l1 l.
Proof.
intro H.
dependent induction H.
- destruct l1.
+ constructor.
+ discriminate.
- apply subseq_there.
exact (IHsubseq _ _ eq_refl).
- destruct l1.
+ apply subseq_nil.
+ injection x as [] prf_seq.
apply subseq_here.
exact (IHsubseq _ _ prf_seq).
Qed.
答案 3 :(得分:0)
基于解构列表的思想,这是在Idris中为完整性所做的证明的一个版本。事实证明,除非我解构隐式参数,否则Idris会局促不安。
data Subseq : List a -> List a -> Type where
Base : Subseq [] []
There : Subseq seq l -> Subseq seq (x :: l)
Here : Subseq seq l -> Subseq (x :: seq) (x :: l)
subseq_empty : Subseq [] l
subseq_empty {l = []} = Base
subseq_empty {l = (x :: xs)} = There subseq_empty
subseq_snd : Subseq (l1 ++ l2) l -> Subseq l1 l
subseq_snd {l1 = []} {l} _ = subseq_empty
subseq_snd {l1 = (x :: xs)} {l = (y :: ys)} (There z) = There (subseq_snd z)
subseq_snd {l1 = (x :: xs)} {l = (x :: ys)} (Here z) = Here (subseq_snd z)
除了解构的隐式参数外,这也是对证明应有的想象。
尽管Little Typer最终赞扬了Coq风格的策略,但是从上面可以明显看出,确实有理由像Idris那样做。