这是我对回文的归纳定义:
Inductive pal { X : Type } : list X -> Prop :=
| pal0 : pal []
| pal1 : forall ( x : X ), pal [x]
| pal2 : forall ( x : X ) ( l : list X ), pal l -> pal ( x :: l ++ [x] ).
我想要证明的定理来自 Software Foundations :
Theorem rev_eq_pal : forall ( X : Type ) ( l : list X ),
l = rev l -> pal l.
我的证据非正式概述如下:
假设
l0
是l0 = rev l0
的任意列表。然后必须保持以下三种情况之一。l0
有:(a)零元素,在这种情况下,根据定义它是回文。
(b)一个元素,在这种情况下,根据定义它也是一个回文。
(c)两个或更多元素,在这种情况下
l0 = x :: l1 ++ [x]
用于某个元素x
,有些列表l1
用于l1 = rev l1
。现在,从
l1 = rev l1
开始,以下三种案例中的一种必须持有......递归案例分析将针对任何有限列表
l0
终止,因为分析列表的长度在每次迭代时减少2。如果它终止于任何列表ln
,它的所有外部列表都是l0
也是回文,因为通过在回文的两端附加两个相同元素构建的列表也是回文。
我认为推理是合理的,但我不确定如何将其形式化。它可以变成Coq的证明吗?关于战术如何运作的一些解释将特别有用。
答案 0 :(得分:10)
这是一个很好的例子,其中"直接"归纳法根本不能很好地工作,因为你不能直接在尾部进行递归调用,而是在尾部的部分。在这种情况下,我通常建议用列表的长度来陈述你的引理,而不是列表本身。然后你可以专门化它。那将是这样的:
Lemma rev_eq_pal_length: forall (X: Type) (n: nat) (l: list X), length l <= n -> l = rev l -> pal l.
Proof.
(* by induction on [n], not [l] *)
Qed.
Theorem rev_eq_pal: forall (X: Type) (l: list X), l = rev l -> pal l.
Proof.
(* apply the previous lemma with n = length l *)
Qed.
如有必要,我可以更详细地帮助您,只需发表评论。
祝你好运!诉P>
编辑:只是为了帮助你,我需要以下的引理来做出这个证据,你也可能需要它们。
Lemma tool : forall (X:Type) (l l': list X) (a b: X),
a :: l = l' ++ b :: nil -> (a = b /\ l = nil) \/ exists k, l = k ++ b :: nil.
Lemma tool2 : forall (X:Type) (l1 l2 : list X) (a b: X),
l1 ++ a :: nil = l2 ++ b :: nil -> a = b /\ l1 = l2.
答案 1 :(得分:2)
您还可以从有充分理由的归纳法中获得归纳原理。
Notation " [ ] " := nil : list_scope.
Notation " [ x1 ; .. ; x2 ] " := (cons x1 .. (cons x2 nil) ..) : list_scope.
Open Scope list_scope.
Conjecture C1 : forall t1 f1 p1, (forall x1, (forall x2, f1 x2 < f1 x1 -> p1 x2) -> p1 x1) -> forall x1 : t1, p1 x1.
Conjecture C2 : forall t1 p1, p1 [] -> (forall x1 l1, p1 ([x1] ++ l1)) -> forall l1 : list t1, p1 l1.
Conjecture C3 : forall t1 p1, p1 [] -> (forall x1 l1, p1 (l1 ++ [x1])) -> forall l1 : list t1, p1 l1.
Conjecture C4 : forall t1 (x1 x2 : t1) l1, length l1 < length ([x1] ++ l1 ++ [x2]).
Theorem T1 : forall t1 p1,
p1 [] ->
(forall x1, p1 [x1]) ->
(forall x1 x2 l1, p1 l1 -> p1 ([x1] ++ l1 ++ [x2])) ->
forall l1 : list t1, p1 l1.
Proof.
intros t1 p1 h1 h2 h3.
induction l1 as [l1 h4] using (C1 (list t1) (@length t1)).
induction l1 as [| x1 l1] using C2.
eapply h1.
induction l1 as [| x2 l1] using C3.
simpl.
eapply h2.
eapply h3.
eapply h4.
eapply C4.
Qed.
你可以通过首先将假设应用于结论,然后在C1
上使用结构归纳,然后使用关于f1 x1
的一些事实来证明猜想<
。
要证明没有归纳假设的C3
,您首先在is_empty l1
上使用案例分析,然后使用事实is_empty l1 = true -> l1 = []
和is_empty l1 = false -> l1 = delete_last l1 ++ [get_last l1]
({{1}将需要一个默认值。)