I'm trying to formulate a problem so that only rewriting will be sufficient to prove the goal. I want to avoid "clever" uses of Propositions and instead use bools that can be computed by Coq.
I define a boolean test function member
that returns true iff an element is in a list,
and different
that returns true iff no element is in both lists.
I want to prove that I can rewrite different
into an expression only using member
.
Theorem different_member: forall xs ys y,
different xs ys = ((negb (member y ys)) || negb (member y xs)).
(The (negb X || Y)
form is the boolean implication).
As a warm-up and reality check I want to prove
Theorem diff_mem:
forall xs ys,
different xs ys = true -> forall y, member y xs = true -> ~ member y ys = true.
The way to proceed is by induction on xs, but I keep messing up on the final step.
Very grateful for some help on both of the theorems! Here is the relevant part of development.
Require Import Arith.
Require Import List.
Require Import Bool.
Import List.ListNotations.
Open Scope list.
Open Scope bool.
Fixpoint member x ys :=
match ys with
| [] => false
| y :: ys' => (beq_nat x y) || (member x ys')
end.
Lemma mem1: forall x, member x [] = false.
Proof. auto. Qed.
Lemma mem2: forall x y l, member x (y::l) = (beq_nat x y) || (member x l).
Proof. auto. Qed.
Fixpoint different xs ys :=
match xs with
| [] => true
| x::xs' => (negb (member x ys)) && (different xs' ys)
end.
Lemma diff1: forall ys, different [] ys = true.
Proof. auto. Qed.
Lemma diff2: forall x xs ys,
different (x::xs) ys = (negb (member x ys)) && (different xs ys).
Proof. auto. Qed.
Theorem diff_mem1: forall xs ys, different xs ys = true -> forall y, member y xs = true -> ~ member y ys = true.
Proof.
Abort.
Theorem different_member:
forall xs ys y, different xs ys =
((negb (member y ys)) || negb (member y xs)).
Proof.
Abort.
EDIT:
Here is a proof of the diff_mem1
theorem. (sleeping on it, and thinking before starting to bang on it in ProofGeneral sometimes helps...). The proof of the other theorem follows the same structure.
However, the question and ultimate goal is still how to solve it entirely with rewrites and hints, so that one could (almost) do induction xs; auto.
.
Theorem diff_mem1: forall xs ys,
different xs ys = true -> forall y, member y xs = true -> ~ member y ys = true.
Proof.
induction xs as [|a xs]; intros ys Hdiff y Hxs Hys.
- inversion Hxs.
- (* we assume y is a member of ys, and of (a::xs) *)
(* it is also assumed that (a::xs) is different from ys *)
(* consider the cases y=a and y<>a *)
remember (beq_nat y a) as Q; destruct Q.
+ (* this case is absurd since y is a member of both ys and (y::xs) *)
apply eq_sym in HeqQ; apply beq_nat_true in HeqQ.
subst a.
simpl in Hdiff.
rewrite Hys in Hdiff.
inversion Hdiff.
+ (* this case is also absurd since y is a member of both ys and xs *)
simpl in Hdiff, Hxs.
rewrite <- HeqQ in Hxs.
simpl in Hxs.
rewrite Bool.andb_true_iff in Hdiff; destruct Hdiff as [_ Hdiff1].
destruct (IHxs ys Hdiff1 y Hxs Hys).
Qed.
EDIT2:
I will close this as @Arthur gave the correct answer as to why I failed in the initial attempt, but for completeness I want to add a solution along the lines of what I was aiming for.
I wrote an Ltac tactic my_simple_rewrite
that does a number of try rewrite with lemma_x in *
(about 20 different lemmas, that are only re-written from left to right). They are simple lemmas about bool
s and the mem1
, mem2
, diff1
, and diff2
from above. To prove the theorem I used it, and only specified the induction variable xs
and which bool
expressions to do a case analysis on (using a home-made Ltac bool_destruct
), and got the following proof.
Theorem different_member:
forall xs ys, different xs ys = true ->
forall y, ((negb (member y ys)) || negb (member y xs)) = true.
Proof.
induction xs as [| a xs]; intros; my_simple_rewrite.
- congruence.
- try
match goal with
| [ HH:_ |- _] => (generalize (IHxs ys HH y); intro IH)
end;
bool_destruct (member a ys);
bool_destruct (member y ys);
bool_destruct (member a xs);
bool_destruct (member y xs);
bool_destruct (beq_nat y a);
my_simple_rewrite;
congruence.
Qed.
The idea is that this can almost be automated. Picking which terms to destruct can be automated, and notice that it tries to instantiate the induction hypotheisis with anything it can throw a stick at - ("if it works, fine! otherwise try the next alternative...").
For future reference, the full development is in https://gist.github.com/larsr/10b6f4817b5117b335cc
Import List.ListNotations.
, not finding that module (also with several variations like addingRequire
or removing theList.
prefix etc.) Removing that line and addingNotation "[]" := nil.
makes the example usable for me. I'll experiment a bit and see if I can help… – nobodyImport ListNotations
– Konstantin Weitz… = false
, and then you'd still have to shuffle around thebool
s in non-obvious ways to gettrue = false
, whereas withProp
s you'd haveFalse
at that point and could just kill it off. With helper lemmas for… = true -> …
and… = false -> …
for various things this will probably be easier, but that'd be a lot of work. The "standard" approach(?) of having aProp
and reflecting back and forth (at least for getting the basic helper lemmas) is probably simpler. Why not try that? – nobody