我正在进行一项练习,在那里我提出了一个证明但我被困住的命题。希望有人并启发我的想法。
我定义了一个定义子序列关系的归纳命题,其中第一个列表中的元素需要按顺序出现在第二个列表中,但不一定是连续出现。
这是我的定义:
Inductive subseq : list nat -> list nat -> Prop :=
| emptyseq : forall l, subseq [] l
| matchh : forall h l1 l2, subseq l1 l2 -> subseq (h :: l1) (h :: l2)
| nmatchh : forall h l1 l2, subseq l1 l2 -> subseq l1 (h :: l2).
和我要证明的定理:
Theorem subseq_shrink : forall h l1 l2,
subseq (h :: l1) l2 -> subseq l1 l2.
基本上它表示如果头部被切断,列表仍将是子序列。很直观,不是吗?但是,我被困住了。
以下是我的证明的一部分:
Proof.
intros h l1 l2 H. generalize dependent h. induction l1.
- intros. apply emptyseq.
- intros h H.
证明看起来并不好看。
1 subgoals
x : nat
l1 : list nat
l2 : list nat
IHl1 : forall h : nat, subseq (h :: l1) l2 -> subseq l1 l2
h : nat
H : subseq (h :: x :: l1) l2
______________________________________(1/1)
subseq (x :: l1) l2
对我来说看起来很无能为力。我在某个地方犯了错误吗?我错过了哪一部分被困在这个简单的定理中?
答案 0 :(得分:2)
您可以在subseq
推导时使用归纳法。请注意下面的remember
:我们需要它,因为Coq使用类型族索引的方式。我认为它是在Software Foundations一书中的某个地方描述的。尝试删除它,看看会发生什么。
Theorem subseq_shrink : forall h l1 l2,
subseq (h :: l1) l2 -> subseq l1 l2.
Proof.
intros h l1 l2 H.
remember (h :: l1) eqn:Eq.
induction H.
- inversion Eq.
- inversion Eq; clear Eq; subst.
now constructor.
- destruct l0; inversion Eq; clear Eq; subst.
now constructor; apply IHsubseq.
Qed.
答案 1 :(得分:2)
这里有多种解决方案。但重要的是要理解为什么我们需要归纳。实际上,我们想要删除h
前面的l1
。由于subseq
的定义,我们知道h
是l2
的第一个元素,或者,如果不是,它将是第二个,或者,如果不是,它将是第三,或......
实际上,我们需要在h
中找到l2
,为此我们需要在l2
上进行归纳,而不是l1
。按照另一个答案的建议对subseq
进行归纳也有助于在h
中找到l2
,这就是为什么它也能正常工作。
在l2
上进行归纳似乎更简单。这是证明的开始:
Theorem subseq_shrink : forall h l1 l2,
subseq (h :: l1) l2 -> subseq l1 l2.
Proof.
intros h l1 l2. revert h l1. induction l2; intros.