当归纳法删除太多信息以致无法解决目标时该怎么办?

时间:2019-05-03 07:54:10

标签: coq

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 = [],但是由于没有前提,我也不能证明这一点。在这里应该做什么?

4 个答案:

答案 0 :(得分:2)

您需要对l1l进行归纳,并使用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那样做。