是否可以强迫归纳策略产生更多的方程式?

时间:2018-08-25 07:50:08

标签: coq

我在玩归纳性命题。我有以下归纳定义:

Inductive subseq {X : Type} : list X -> list X -> Prop :=
| empty_subseq : subseq [ ] [ ]
| subseq_left_elim : forall (l1 l2 : list X) (x : X),
              subseq (x :: l1) l2 -> subseq l1 l2
| subseq_intro : forall (l1 l2 : list X) (x : X),
              subseq l1 l2 -> subseq (x :: l1) (x :: l2).

Notation "l <<< k" := (subseq l k) (at level 10).

我正试图证明这样一个引理:

Lemma subseq_right_elim : forall (X : Type) (l1 l2 : list X) (x y : X),  
  (x :: l1) <<< (y :: l2) -> x = y \/ (x :: l1) <<< l2.
Proof.
  intros X l1 l2 x y H.
  induction H as [| l1' l2' z E IH | l1' l2' z E IH ].
  + right. apply empty_subseq_l. 
    (* empty_subseq_l : forall (X : Type) (l : list X), [ ] <<< l. *)
  + destruct IH as [IH | IH].
    * left. apply IH.
    * right. apply subseq_left_elim with z.
      apply IH.
  + (* stuck *)
Abort.

我不知道如何证明subseq_intro的情况。这似乎是真的,因为非正式地,如果将subseq_intro应用于产生(x :: l1) <<< (y :: l2),则xy必须相等,并且这只是目标。但是在第三种情况下,Coq没有提供这样的断言。如何强制执行此操作,就像是否应用了反转策略?

1 个答案:

答案 0 :(得分:4)

如何获得原始问题的解决方案

您可以使用remember策略,因为induction(和destruct)“忘记了” indices的确切形状。在类型arg1 <<< arg2中,arg1arg2都是索引。顺便提一下,James Wilcox的this blog post详细解释了它的工作原理。无论如何,如果要对归纳类型族进行归纳,则通常希望索引是变量(带有额外的方程式,可以保留所有需要的信息)。

所以,如果您这样开始:

remember (x :: l1) as xl1 eqn: E1.
remember (y :: l2) as xl2 eqn: E2.

您得到了方程式,但最终将遇到麻烦,因为归纳假设将不可用。为了使它们可用,只需简单地归纳归纳假设即可

revert x y l1 l2 E1 E2.

更明确的说,你就是这样开始的

Lemma subseq_right_elim (X : Type) (l1 l2 : list X) (x y : X) :
  (x :: l1) <<< (y :: l2) -> (x = y) \/ (x :: l1) <<< l2.
Proof.
  intros H.
  remember (x :: l1) as xl1 eqn: E1; remember (y :: l2) as xl2 eqn: E2.
  revert x y l1 l2 E1 E2.
  induction H as [| l1' l2' z S IH | l1' l2' z S IH ]; intros x y l1 l2 E1 E2.

就其价值而言,引理的陈述不够笼统,因此归纳法无济于事–这次您将能够解决第三个子目标,但不能解决第二个子目标。为了克服这个困难,使引理的陈述更像subseq_left_elim

SPOILER ALERT this gist拥有充分的证据。

更好的方法是重新定义归纳谓词

现在,您遇到的困难源于the回定义子序列概念的方式。通过一个非常简单的示例的证明,您可以更清楚地看到它:

Goal [1; 3; 5] <<< [0; 1; 2; 3; 4; 5; 6].
Proof.
apply subseq_left_elim with 0. apply subseq_intro.
apply subseq_intro.
apply subseq_left_elim with 2. apply subseq_intro.
apply subseq_intro.
apply subseq_left_elim with 4. apply subseq_intro.
apply subseq_intro.
apply subseq_left_elim with 6. apply subseq_intro.
apply empty_subseq.
Qed.

基本上,您必须扩大目标的大小才能在以后缩小目标。

您是否选择了更简单的编码,例如

Reserved Notation "l <<< k" (at level 10).
Inductive subseq {X : Type} : list X -> list X -> Prop :=
| empty_subseq : [ ] <<< [ ]
| subseq_drop_right l1 l2 x : l1 <<< l2 ->       l1  <<< (x :: l2)
| subseq_drop_both l1 l2 x  : l1 <<< l2 -> (x :: l1) <<< (x :: l2)
where "l <<< k" := (subseq l k).

您的生活会更加轻松!例如。这是上述简单事实的新证明:

Goal [1; 3; 5] <<< [0; 1; 2; 3; 4; 5; 6].
apply subseq_drop_right.
apply subseq_drop_both.
apply subseq_drop_right.
apply subseq_drop_both.
apply subseq_drop_right.
apply subseq_drop_both.
apply subseq_drop_right.
apply empty_subseq.
Qed.

这一次您只是将目标减小了一步。