Prove "rev (rev l) = l" in Coq - coq

This is one of the exercise given to me, I got stuck almost immediately after doing an induction on l. I dont know what other assertion to make here.
I'm not allowed to use advanced tactics like auto, intuition etc.
Fixpoint snoc {A : Type} l a : list A :=
match l with
| nil => a :: nil
| h :: t => h :: (snoc t a)
end.
Fixpoint rev {A : Type} l : list A :=
match l with
| nil => nil
| h :: t => snoc (rev t) h
end.
(Prove the following)
Theorem rev_rev : forall A (l : list A),
rev (rev l) = l.

We have all been new to this, and in the beginning it is useful to get help to not get stuck an lose courage when trying to master a new subject. I'll try to give you a hint without giving away too much.
The reason why this is trickier than earlier exercises may be because this proof involves doing two inductive reasoning steps. You probably did the first one just fine and got the second goal like
...
IHl : rev (rev l) = l
============================
rev (snoc (rev l) a) = a :: l
Unfortunately you can't use your inductive hypothesis IHl immediately, because the argument to rev is not in the right shape.
So, here you could try to prove another lemma about rev (snoc l a) = ... that would turn the goal into something which you could rewrite with IHl.
If you can figure that out, and prove that in a lemma, then you should be fine.

We won't do your homework for you, you should first prove it on pen & paper as #gallais said.
A tip: you might need to generalize your property a little (use an intermediate lemma) to be able to prove rev_rev. You should have a look at rev_append.

Related

Coq: Rewriting with 'forall' in hypothesis or goal

I have proved 'correctness' of the reverse function on polymorphic Lists in Coq. The following proof works just fine, but I have a few questions about how the rewrite tactic works.
Here's the code:
Require Export Coq.Lists.List.
Import ListNotations.
Fixpoint rev {T:Type} (l:list T) : list T :=
match l with
| nil => nil
| h :: t => rev t ++ [h]
end.
(* Prove rev_acc equal to above naive implementation. *)
Fixpoint rev_acc {T:Type} (l acc:list T) : list T :=
match l with
| nil => acc
| h :: t => rev_acc t (h::acc)
end.
Theorem app_assoc : forall (T:Type) (l1 l2 l3 : list T),
(l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3).
Proof.
Admitted.
Theorem rev_acc_correct : forall (T:Type) (l k :list T),
rev l ++ k = rev_acc l k.
Proof.
intros T l.
induction l as [ | h l' IHl' ].
- reflexivity.
- simpl.
intro k.
(* Why is "intro k" required for "rewrite -> app_assoc" *)
(* But "rewrite -> IHl'" works regardless of "intro k". *)
(* generalize (rev l'), [h], k. *)
rewrite -> app_assoc.
simpl.
rewrite -> IHl'.
reflexivity.
Qed.
In the inductive step of the proof for rev_acc_correct if I skip intro k, then rewriting with app_assoc complains that it cannot find a matching subterm.
Found no subterm matching "(?M1058 ++ ?M1059) ++ ?M1060" in the current goal.
Here, I presume that the ? before the placeholder names denote that the terms are constrained, in this case to be of type List T for some type T; and since rev l' and [h] in the goal are instances of List T, one would expect a match in the goal.
On the other hand, rewriting with inductive hypothesis(rewrite -> IHl') instead of app_assoc goes through without needing an intro k before.
I find this behaviour of rewrite a bit confusing and the Coq manual doesn't provide any details. I don't want to have to read through the implementation but I need a good operational understanding of what the rewrite tactic does, especially with regards to how term matching works. Any answers/references in this direction are highly appreciated.
The complication with this rewrite is that there's a binder (the forall k), which can complicate things. If you just want things to work, use setoid_rewrite instead of rewrite and it will rewrite under binders.
rewrite IHl' looks like it happens under a binder, but the pattern being re-written doesn't actually involve the bound variable, so the binder isn't actually important. Here's what I mean: the goal is
forall k : list T, (rev l' ++ [h]) ++ k = rev_acc l' (h :: k)
which is the same thing as (that is, equal to):
(fun l : list T => forall k : list T, l ++ k = rev_acc l' (h :: k)) (rev l' ++ [h])
which I got using pattern (rev l' ++ [h]) in Ltac. Now it's clear that you can just rewrite the part being applied to and ignore the binder. When you do rewrite IHl' Coq easily figures out that IHl should be specialized to [h] and the rewrite proceeds.
rewrite app_assoc, on the other hand, needs to be specialized to three lists, specifically rev l', [h], and k. It can't be specialized in the current context because the variable k is only bound underneath the forall. This is why the pattern (?x ++ ?y) ++ ?z doesn't appear in the goal.
So what do you actually do? You can of course introduce k so there is no binder, but there's a simpler and more general technique: Coq has generalized rewriting that can rewrite under binders, which you can use by instead calling setoid_rewrite (see Rewriting under binders in the Coq reference manual). The manual tells you you need to declare morphisms, but the relevant ones have all been implemented for you in this case for forall, so setoid_rewrite app_assoc will just work.
Note that while you can always introduce a forall to get rid of the binder, setoid_rewrite can be really handy when your goal is an exists. Rather than using eexists you can just rewrite under the binder.

Program Fixpoint: recursive call in `let` and hypothesis of the obligation

Say I have the following Program Fixpoint:
From Coq Require Import List Program.
Import ListNotations.
Program Fixpoint f l {measure (length l)}: list nat :=
let f_rec := (f (tl l) ) in
match hd_error l with
| Some n => n :: f_rec
| None => []
end.
(This example basically returns l in a very stupid way, for the sake of having a simple example).
Here, I have a recursive call to f (stored in f_rec) which is only used if l contains an element, which ensures that when I use f_rec, length (tl l) is indeed smaller than length l.
However, when I want to solve the obligation
Next Obligation.
I don't have the hypothesis hd_error l = Some n which I need.
(Somehow, I have the impression that it is understood as "compute f (tl l) at the let in place", and not "delay the computation until it is actually used").
To illustrate the difference, if I "inline" the let ... in statement:
Program Fixpoint f l {measure (length l)}: list nat :=
match hd_error l with
| Some n => n :: (f (tl l) )
| None => []
end.
Next Obligation.
destruct l.
Here I have Heq_anonymous : Some n = hd_error [] in the environment.
My question is the following:
is it possible to have the hypothesis I need, i.e. to have the hypothesis generated by the match ... with statement ?
N.B.: Moving the let is a solution, but I am curious to know whether this is possible without doing so. For instance, it might be useful in the case f_rec is used in various contexts, to avoid duplicating f (tl l).
One trick is to explicitly ask for the hypothesis you need (I recently saw it in this answer by Joachim Breitner):
let f_rec := fun pf : length (tl l) < length l => f (tl l) in
This way you will be able to use f_rec only when it makes sense.
Program Fixpoint f l {measure (length l)}: list nat :=
let f_rec := fun pf : length (tl l) < length l => f (tl l) in
match hd_error l with
| Some n => n :: f_rec _
| None => []
end.
Next Obligation. destruct l; [discriminate | auto]. Qed.

Coq - undocumented error on induction with eqn:

Using Coq 8.4pl3, I'm getting an error on induction with the eqn: variant that is not listed under induction in the reference manual.
(* Export below requires Software Foundations 4.0. *)
Require Export Logic.
Inductive disjoint (X : Type) (l1 l2 : list X) : Prop :=
| nil1 : l1 = [] -> disjoint X l1 l2
| nil2 : l2 = [] -> disjoint X l1 l2
| bothCons : forall x:X,
In x l1 ->
not (In x l2) ->
disjoint X l1 l2.
Fixpoint head (X : Type) (l : list X) : option X :=
match l with
| [] => None
| h :: t => Some h
end.
Fixpoint tail (X : Type) (l : list X) : list X :=
match l with
| [] => []
| h :: t => t
end.
Inductive NoDup (X : Type) (l : list X) : Prop :=
| ndNil : l = [] -> NoDup X l
| ndSingle : forall x:X, l = [x] -> NoDup X l
| ndCons : forall x:X, head X l = Some x ->
not (In x (tail X l)) /\ NoDup X (tail X l) ->
NoDup X l.
Theorem disjoint__app_NoDup :
forall (X : Type) (l1 l2 : list X),
disjoint X l1 l2 /\ NoDup X l1 /\ NoDup X l2 ->
NoDup X (l1 ++ l2).
Proof.
intros. induction H eqn:caseEqn.
If I substitute just plain "induction H" for the last step, I get no error, but with the above eqn: argument, I get the error:
Error: a is used in conclusion.
(Previously there was a condition missing in the theorem statement, and the same error listed an identifier d instead.)
Ref manual lists "is used in conclusion" as an error from use of assert. It makes some kind of sense that behind the scenes, eqn: might be generating assertions, but I have no identifier a visible in the context, and I can't see what Coq is trying to automatically do with it.
Tried replacing beginning of the proof with
intros. remember H. induction H.
Now the attempt to do induction gives the same error as before, only with H instead of a. (When the theorem was missing the additional condition, Coq also explicitly added a d to the context, identical to the hypothesis H.)
How can I move forward here? I'm trying to avoid losing information from the context.
This is a minor bug; I've reported it. However, the thing you are trying to do here is not particularly sensible. Note that you are invoking induction on a conjunction (/\), and asking Coq to leave you an equation that says that the original hypothesis is equal to the conjunction of the two generated proofs. There are two issues here:
Your hypothesis is not used in a dependent fashion anywhere, so you don't need to remember it.
Your hypothesis is not recursive, so you could just as well do destruct H rather than induction H.
As for the error message, it becomes a bit more clear if you note that replacing /\ with * makes induction H eqn:caseEqn go through, and breaks your hypothesis apart into two parts named a and b. The actual issue is that the proof term constructed by induction H eqn:... is ill-typed when H's type is a Prop, because you cannot eliminate Props to get information. I suspect that the code simply tries to do something with the a that it creates in a particular way, and assumes that any failure to do that must be because a is used in the conclusion, rather than because the proof term it was creating was ill-formed.

Reasoning about lists in Coq

I'm try to solve some theorems, based on Pierce's "Software Foundations".
First of all I create a couple of useful functions:
Inductive natlist: Type :=
| nil: natlist
| cons : nat -> natlist -> natlist.
Notation "x :: l" := (cons x l) (at level 60, right associativity).
Fixpoint repeat (n count: nat): natlist :=
match count with
| O => nil
| S count' => n :: (repeat n count')
end.
Fixpoint length (l: natlist): nat :=
match l with
| nil => O
| h :: t => S (length t)
end.
Theorem count_repeat: forall n: nat, length (repeat n n) = n.
Proof.
intros n. induction n as [| n'].
simpl. reflexivity.
simpl. (* and here I can't continue... *)
I want to follow Pierce's advice:
Note that, since this problem is somewhat open-ended, it's possible
that you may come up with a theorem which is true, but whose proof
requires techniques you haven't learned yet. Feel free to ask for help
if you get stuck!
So, could you please advice some proof techniques for me?
As #eponier said, you should try to prove a more general lemma, like
Theorem count_repeat_gen: forall m n: nat, length (repeat n m) = m.
Using repeat n n creates an implicit link between the value of the element and the size of the list which makes your statement impossible to prove directly. Once you proved count_repeat_gen, you'll be able to prove your theorem.

Impossible pattern in writing implicit proof object in coq

I trying to use coq as a programming language with dependent type. I created the following small program:
Inductive Good : list nat -> Set :=
| GoodNonEmpty : forall h t, Good (h :: t).
Definition get_first(l : list nat)(good : Good l) : nat :=
match l with
| h :: t => h
| nil =>
match good with
end
end.
I defined a type for non empty list and create a function which gets the first element of such a list provided there's a proof that it's not empty. I handle well the case where head items consists of two items, but I can't handle the impossible case of empty list. How can I do this in coq?
One way to do it that is simpler than your try is:
Definition get_first (l : list nat) (good : Good l) : nat :=
match good with
| GoodNonEmpty h _ => h
end.
Here is a way to do it in the way you wanted to do it. You'll notice it is very verbose to prove that "Good nil" does not exist, inlined.
Definition get_first (l : list nat) (good : Good l) : nat :=
(
match l as l' return (Good l' -> nat) with
| nil =>
fun (goodnil : Good nil) =>
(
match goodnil in (Good l'') return (nil = l'' -> nat) with
| GoodNonEmpty h t =>
fun H => False_rect _ (nil_cons H)
end
)
(#eq_refl _ nil)
| h :: _ => fun _ => h
end
) good.
You can surely define some of that outside and reuse it. I am not aware of the best practices though. Maybe someone can come with a shorter way to do the same thing.
EDIT:
By the way, you can get to pretty much the same result, in a much easier way, in proof mode:
Definition get_first' (l : list nat) (good : Good l) : nat.
Proof.
destruct l. inversion good. exact n.
Defined.
You can then:
Print get_first'.
To see how Coq defines it. However, for more involved things, you might be better off following what gdsfhl from the #coq IRC channel proposed as a solution:
http://paste.in.ua/4782/
You can see that he uses the refine tactic to provide part of the skeleton of the term to write, and defer the missing proofs.