问题
Here is my inductive definition of palindromes:
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] ).
And the theorem I want to prove, from Software Foundations:
Theorem rev_eq_pal : forall ( X : Type ) ( l : list X ),
l = rev l -> pal l.
My informal outlines of the proof are as follows:
Suppose
l0
is an arbitrary list such thatl0 = rev l0
. Then one of the following three cases must hold.l0
has:(a) zero elements, in which case it is a palindrome by definition.
(b) one element, in which case it is also a palindrome by definition.
(c) two elements or more, in which case
l0 = x :: l1 ++ [x]
for some elementx
and some listl1
such thatl1 = rev l1
.Now, since
l1 = rev l1
, one of the following three cases must hold...The recursive case analysis will terminate for any finite list
l0
because the length of the list analyzed decreases by 2 through each iteration. If it terminates for any listln
, all of its outer lists up tol0
are also palindromes, since a list constructed by appending two identical elements at either end of a palindrome is also a palindrome.
I think the reasoning is sound, but I'm not sure how to formalize it. Can it be turned into a proof in Coq? Some explanations of how the tactics used work would be especially helpful.
回答1:
This is a nice example where "direct" induction does not work well at all because you don't directly make the recursive call on the tail, but on part of the tail. In such cases, I usually advice to state your lemma with the length of the list, not on the list itself. You can then specialize it. That would be something like:
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.
I can help you in more detail if necessary, just leave a comment.
Good luck !
V.
EDIT: just to help you, I needed the following lemmas to make this proof, you might need them too.
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.
回答2:
You could also derive your induction principle from a form of well-founded induction.
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.
You can prove conjecture C1
by first applying the hypothesis to the conclusion, then using structural induction on f1 x1
, and then using some facts about <
.
To prove C3
, which has no induction hypothesis, you first use case analysis on is_empty l1
, and then use the facts is_empty l1 = true -> l1 = []
and is_empty l1 = false -> l1 = delete_last l1 ++ [get_last l1]
(get_last
will need a default value).
来源:https://stackoverflow.com/questions/24363319/proving-that-a-reversible-list-is-a-palindrome-in-coq