I have the following (hopefully non-controversial!) definition of heterogeneous vectors:
Require Vectors.Vector.
Import Vector.VectorNotations.
Section hvec.
Variable A : Type.
Variable B : A -> Type.
Inductive t : forall k : nat, Vector.t A k -> Type :=
| nil : t 0 []
| cons :
forall (a : A) (b : B a) (k : nat) (v : Vector.t A k), t k v -> t (S k) (a :: v).
Local Notation "[! ]" := nil (format "[! ]").
Local Notation "h :! t" := (cons _ h _ _ t) (at level 60, right associativity).
Local Notation "[! x ]" := (x :! [! ]).
I'd like to define an eqb function (assuming there's one for the component types). To define one, I think I need something like a rect2. Following on from the Vectors library by analogy, I think its type should be something like this:
Fixpoint rect2
(P : forall {k : nat} {v : Vector.t A k} (hv0 hv1 : t k v), Type)
(bas : P nil nil)
(rect : forall {k : nat} {v : Vector.t A k} {hv0 hv1 : t k v},
P hv0 hv1 ->
forall (a : A) (b0 b1 : B a), P (b0 :! hv0) (b1 :! hv1))
{k : nat}
: forall (v : Vector.t A k) (hv0 hv1 : t k v), P hv0 hv1.
The problem is that I can't work out how to get all the dependent types to go through properly. Matching on k, then v then hv0 (which seemed like the obvious approach to me) doesn't seem to work. The problem is that you get this far:
refine (
match k with
| 0 =>
fun v =>
match v with
| [] =>
fun hv0 hv1 => _
| _ => tt
end
| S k' => _
end
).
but then can't match on hv0 sensibly. With no return annotation (match hv0 with ...), the types look like this:
...
v : Vector.t A 0
hv0, hv1 : t 0 []
============================
P 0 [] hv0 hv1
(note the hv0 in the obligation, not a nil). Trying to write return annotations like match hv0 as hv0' return P 0 [] hv0' hv1 with ... doesn't help because now the type of hv0' has lost the fact that k was zero.
I assume there's a clever trick / correct order to write this sort of thing. Could someone help?
You can do the inversion with an involved dependent pattern match as follows:
Fixpoint rect2
(P : forall {k : nat} {v : Vector.t A k} (hv0 hv1 : t k v), Type)
(bas : P nil nil)
(rect : forall {k : nat} {v : Vector.t A k} {hv0 hv1 : t k v},
P hv0 hv1 ->
forall (a : A) (b0 b1 : B a), P (b0 :! hv0) (b1 :! hv1))
{k : nat}
: forall (v : Vector.t A k) (hv0 hv1 : t k v), P hv0 hv1.
Proof.
intro v.
induction v using Vector.t_rect.
- intros hv0.
refine (
(* match on hv0, retaining info on its indices *)
match hv0 as z in t k l return forall (hv1 : t k l),
(* match on the abstracted index l : Vector.t A k *)
match l as l' in Vector.t _ k'
return forall (hv0 hv1 : t k' l'), Type
with
(* when l = [] we have our goal *)
| [] => P 0 []
(* otherwise we create a dummy goal that we can fulfill *)
| _ => fun _ _ => unit
end z hv1
with
| [!] => _ (* Actual goal with hv0 replaced by [!] *)
| _ => fun _ => tt (* Dummy goal of type unit *)
end).
Playing a bit with these kinds of pattern matches can teach you how dependent types work (or not) but it quickly becomes tedious. To go further, the Equations library provides some utilities to handle type dependency and in particular to help with this kind of dependent inversions.
Here is a complete solution using Equations:
Require Vectors.Vector.
Import Vector.VectorNotations.
From Equations Require Import Equations.
Module VectorInd.
(* Provided by Equations *)
Derive Signature NoConfusionHom for Vector.t.
End VectorInd.
Import VectorInd.
Section hvec.
Variable A : Type.
Variable B : A -> Type.
Inductive t : forall k : nat, Vector.t A k -> Type :=
| nil : t 0 []
| cons :
forall (a : A) (b : B a) (k : nat) (v : Vector.t A k), t k v -> t (S k) (a :: v).
Local Notation "[! ]" := nil (format "[! ]").
Local Notation "h :! t" := (cons _ h _ _ t) (at level 60, right associativity).
Local Notation "[! x ]" := (x :! [! ]).
(* Provided by Equations *)
Derive Signature NoConfusionHom for t.
Fixpoint rect2
(P : forall {k : nat} {v : Vector.t A k} (hv0 hv1 : t k v), Type)
(bas : P nil nil)
(rect : forall {k : nat} {v : Vector.t A k} {hv0 hv1 : t k v},
P hv0 hv1 ->
forall (a : A) (b0 b1 : B a), P (b0 :! hv0) (b1 :! hv1))
{k : nat}
: forall (v : Vector.t A k) (hv0 hv1 : t k v), P hv0 hv1.
Proof.
intro v.
induction v using Vector.t_rect.
all: intros hv0 hv1; depelim hv0; depelim hv1.
- apply bas.
- now apply rect, IHv.
Defined.
Related
I defined this function.
Inductive Euc:nat -> Type:=
|RO : Euc 0
|Rn : forall {n:nat}, R -> Euc n -> Euc (S n).
Notation "[ ]" := RO.
Infix ":::" := Rn (at level 60, right associativity).
Fixpoint QE {A}(b c:Euc A) :=
match b,c with
|b':::bs, c'::: cs => (b'+c') ::: QE bs cs
|_, _ => []
end.
I have encountered the error "The term "[]" has type "Euc 0" while it is expected to have type "Euc A" ".
How do I teach Coq that Euc 0 is Euc A?
Coq doesn't know that the only pattern left is the "RO" constructor, therefore you're not able to return an empty Euc.
To fix that just remove the _ and specialize the case :
Fixpoint QE {A}(b c:Euc A) : Euc A.
refine (match b,c with
|RO, RO => _
|H => ????
end).
That forces coq to understand that you're dealing with a specific constructor.
Also, Coq always will instantiate new variables (Types not) of elimination, thus coq may complain that bs and cs have different indexes.
The coq vectordef library has several examples of how to manage this.
A first approach and more mature it is to use elimination schemes, notice you can destruct a non-zero vector using the head and last.
For example :
Definition rect_euc {n : nat} (v : Euc (S n)) :
forall (P : Euc (S n) -> Type) (H : forall ys a, P (a ::: ys)), P v.
refine (match v with
|#Rn _ _ _ => _
|R0 => _
end).
apply idProp.
intros; apply H.
Defined.
Now, you just have to use the scheme to destruct both vectors preserving the length of both :
Fixpoint QE (n : nat) {struct n} : Euc n -> Euc n -> Euc n :=
match n as c return Euc c -> Euc c -> Euc c with
| S m => fun a =>
(#rect_euc _ a _ (fun xs x b =>
(#rect_euc _ b _ (fun ys y => (x + y) ::: #QE m xs ys))))
| 0 => fun xs ys => []
end.
Alternatively you can use the coq tactics to remember that two indexes are equal :
Fixpoint QE' (n : nat) (b : Euc n) : Euc n -> Euc n.
refine (match b in Euc n return Euc n -> Euc n with
|#Rn m x xs => _
|#RO => fun H => []
end).
remember (S m).
intro H; destruct H as [| k y ys].
inversion Heqn0.
inversion Heqn0.
subst; exact ((x + y) ::: QE' _ xs ys).
Defined.
Following Adam Chlipala's definition of heterogeneous lists, I wanted to define an equivalent of the Forall function on normal lists. This isn't too difficult, and you end up with two constructors as usual. Now suppose that I know that a fact is true about every element of a non-empty list. With normal lists, I could use Forall_inv and Forall_inv_tail to assert that it's true about the head and tail of the list.
I'd like to prove the equivalent for hForall as defined below, starting with the head case. Looking at the source in Lists/List.v, the proof for normal lists is easy and runs by inversion on Forall (a :: l). The equivalent for my hForall gives a mess of dependent variables. Am I missing something obvious?
Require Import List.
Section hlist.
Variable A : Type.
Variable B : A -> Type.
Inductive hlist : list A -> Type :=
| HNil : hlist nil
| HCons {a : A} {ls : list A} : B a -> hlist ls -> hlist (a :: ls).
Section hForall.
Variable P : forall a : A, B a -> Prop.
Inductive hForall : forall {As : list A}, hlist As -> Prop :=
| hForall_nil : hForall HNil
| hForall_cons {a : A} {ls : list A} (x : B a) (hl : hlist ls)
: P a x -> hForall hl -> hForall (HCons x hl).
Lemma hForall_inv
(a : A)
(ls : list A)
(x : B a)
(hl : hlist ls)
: hForall (HCons x hl) -> P a x.
Proof.
(* Help! *)
Abort.
End hForall.
End hlist.
Inductives indexed by indexed types lead to that kind of difficulty.
Alternatively, consider defining hForall as a Fixpoint. Then the inversion lemma follows by just unfolding the definition.
Section hForall'.
Variable P : forall a, B a -> Prop.
Fixpoint hForall' {As : list A} (hs : hlist As) : Prop :=
match hs with
| HNil => True
| HCons x js => P _ x /\ hForall' js
end.
Lemma hForall'_inv
(a : A)
(ls : list A)
(x : B a)
(hl : hlist ls)
: hForall' (HCons x hl) -> P a x.
Proof.
intros []; auto.
Qed.
End hForall'.
Appendix
Mostly for educational purposes, here's a few ways to prove that inversion lemma for the original inductive definition of hForall (starting from the simpler to use).
One solution is the dependent destruction tactic, which also automatically handles heterogeneous equalities, as opposed to destruct. It is imported from the Program module:
Import Program.
Lemma hForall_inv
(a : A)
(ls : list A)
(x : B a)
(hl : hlist ls)
: hForall (HCons x hl) -> P a x.
Proof.
intros H.
dependent destruction H.
auto.
Qed.
The (minor) catch is that it uses some axioms about heterogeneous equality:
Print Assumptions hForall_inv.
(*
Section Variables:
P : forall a : A, B a -> Prop
B : A -> Type
A : Type
Axioms:
Eqdep.Eq_rect_eq.eq_rect_eq : forall (U : Type) (p : U)
(Q : U -> Type) (x : Q p)
(h : p = p), x = eq_rect p Q x p h
JMeq_eq : forall (A : Type) (x y : A), x ~= y -> x = y
*)
With a little more knowledge of how destruct works/dependent pattern-matching, here's a proof without axioms.
There are some detailed explanations of dependent pattern-matching in CPDT, but briefly the issue is that when we do destruct/inversion on hForall (HCons x hl), the index HCons x hl gets generalized before the case-split, so you get a nonsensical case where it is replaced with HNil, and a second case with a different index HCons x0 hl0, and a good way of remembering the (heterogeneous) equality across that generalization is a research-grade problem. You wouldn't need to mess with heterogeneous equalities if the goal just got rewritten with those variables, and indeed you can refactor the goal so that it explicitly depends on HCons x hl, instead of x and hl separately, which will then be generalized by destruct:
Lemma hForall_inv'
(a : A)
(ls : list A)
(x : B a)
(hl : hlist ls)
: hForall (HCons x hl) -> P a x.
Proof.
intros H.
change (match HCons x hl return Prop with (* for some reason you have to explicitly annotate the return type as Prop right here *)
| HNil => True
| HCons x _ => P _ x
end).
destruct H.
- exact I. (* Replace [HCons x hl] with [HNil], the goal reduces to [True]. (This is an unreachable case.) *)
- assumption.
(* Or, directly writing down the proof term. *)
Restart.
intros H.
refine (match H in #hForall As hs return
match hs return Prop with
| HNil => True
| HCons x _ => P _ x
end
with
| hForall_nil => I
| hForall_cons _ _ _ _ => _
end).
assumption.
Qed.
The Equations plugin probably automates that properly, but I haven't tried.
I think the easiest way to solve this kind of destructing is by telling Coq that we care about these destructed patterns.
Alternately, you can use remember tactic, but sometimes it will make more hard reason about your theorem.
Lemma hForall_inv
(a : A)
(ls : list A)
(x : B a)
(hl : hlist ls)
: hForall (HCons x hl) -> P a x.
Proof.
have : forall (F : forall (a : A) (ls : list A) (x : B a) (hl : hlist ls) (H : hForall (HCons x hl)), Prop),
(forall (a : A) (ls : list A) (x : B a) (hl : hlist ls) (H : hForall (HCons x hl)) (I : forall (a : A) (ls : list A) (x : B a) (hl : hlist ls) (f : P a x) (H : hForall (HCons x hl)), F a ls x hl H),
F a ls x hl H).
intros.
refine (match H in (hForall (HCons x hl)) return F _ _ _ _ H with
|hForall_nil => _
|hForall_cons a x y z => _
end).
exact idProp.
exact (I _ _ _ _ y (hForall_cons a x y z)).
move => forall_rect.
elim/forall_rect; by [].
Qed.
An observation I am using Type to enables elimination :
Inductive hForall : forall {As : list A}, hlist As -> Type :=
| hForall_nil : hForall HNil
| hForall_cons {a : A} {ls : list A} (x : B a) (hl : hlist ls)
: P a x -> hForall hl -> hForall (HCons x hl).
Inductive bar {X : Type} : list X -> Prop :=
| bar_nil : bar []
| bar_fst : forall x l, bar (rev l ++ l) -> bar (rev l ++ [x] ++ l)
| bar_snd : forall x l, bar (rev l ++ [x] ++ l) -> bar (rev l ++ [x; x] ++ l).
Axiom bar_surround :
forall X x (l : list X),
bar l -> bar ([x] ++ l ++ [x]).
Inductive list_last {X : Type} : list X -> Prop :=
| ll_nil : list_last []
| ll_snoc : forall l x, list_last l -> list_last (l ++ [x]).
Axiom ll_app :
forall X (a b : list X),
list_last a -> list_last b -> list_last (a ++ b).
Axiom ll_from_list :
forall {X} (l : list X),
list_last l.
Axiom app_head_eq :
forall X (a b c : list X),
a ++ c = b ++ c -> a = b.
Theorem foo :
forall X (l: list X), l = rev l -> bar l.
Proof.
intros.
induction l.
- constructor.
- assert (Hll := ll_from_list l).
inversion Hll.
+ apply (bar_fst x []). apply bar_nil.
+ rewrite <- H1 in H.
simpl in H.
rewrite rev_app_distr in H.
rewrite <- app_assoc in H.
simpl in H.
inversion H.
apply app_head_eq in H4.
apply bar_surround.
1 subgoal
X : Type
x : X
l, l0 : list X
x0 : X
H : x :: l0 ++ [x0] = x0 :: rev l0 ++ [x]
IHl : l = rev l -> bar l
Hll : list_last l
H0 : list_last l0
H1 : l0 ++ [x0] = l
H3 : x = x0
H4 : l0 = rev l0
______________________________________(1/1)
bar l0
I am only a step away from getting this exercise solved, but I do not know how to do the induction step. Note that IHl is useless here and replacing induction on l with induction on Hll would have a similar problem. In both cases, the inductive hypothesis would expect a call with a one step decrease while I need two - one with the item taken from both the start and the end of the list on both sides of the equality.
Consider that the type of the function I am trying to prove is forall X (l: list X), l = rev l -> bar l and I have l0 = rev l0 -> bar l0 in the goal here. l0 is a decreased argument thereby making the recursive call safe.
What should I do here?
You can prove the following inductive predicate:
Inductive delist {A : Type} : list A -> Prop :=
| delist_nil : delist []
| delist_one x : delist [x]
| delist_cons x y l : delist l -> delist (x :: l ++ [y])
.
Theorem all_delist {A} : forall xs : list A, delist xs.
Then in your final theorem, induction on delist xs will split into the cases you need.
Another solution is by strong induction on the length of the list:
Lemma foo_len X : forall (n : nat) (l: list X), length l <= n -> l = rev l -> bar l.
Proof.
induction n.
(* Nat.le_succ_r from the Arith module is useful here *)
...
Qed.
(* Final theorem *)
Theorem foo X : forall (l : list X), l = rev l -> bar l.
Proof.
intros; apply foo_len; auto.
Qed.
This is a more common and systematic principle than delist, but you will need to work more than the ad-hoc inductive type above to use the induction hypothesis in the main proof.
Here is how to implement the first part of what was suggested in the other answer. I can confirm that with this, solving the exercise is quite simple. That having said, I am interested how to solve the above using straightforward induction. Having to implement delist and its functions is more complicated than I'd prefer.
Inductive delist {A : Type} : list A -> Prop :=
| delist_nil : delist []
| delist_one x : delist [x]
| delist_wrap x y l : delist l -> delist (x :: l ++ [y]).
Theorem delist_cons {A} :
forall x (l : list A),
delist l -> delist (x :: l).
Proof.
intros.
generalize dependent x.
induction H; intros.
- constructor.
- replace [x; x0] with (x :: [] ++ [x0]).
2 : { reflexivity. }
+ apply delist_wrap with (l := []). constructor.
- replace (x0 :: x :: l ++ [y]) with (x0 :: (x :: l) ++ [y]).
2 : { reflexivity. }
constructor.
apply IHdelist.
Qed.
Theorem delist_from_list {A} :
forall l : list A,
delist l.
Proof.
induction l.
- constructor.
- assert (ll := ll_from_list l).
destruct ll.
+ constructor.
+ apply delist_cons. assumption.
Qed.
I made a question before, but i think that question was bad formalized so...
I am facing some problems with this specific definition to prove their properties:
I have a definition of a list :
Inductive list (A : Type) (f : A -> A -> A) : A -> Type :=
|Acons : forall {x : A} (y' : A) (cons' : list f x), list f (f x y')
|Anil : forall (x: A) (y : A), list f (f x y).
And that's definitions :
Definition t_list (T : Type) := (T -> T -> T) -> T -> T.
Definition nil {A : Type} (f : A -> A -> A) (d : A) := d.
Definition cons {A : Type} (v' : A) (c_cons : t_list _) (f : A -> A -> A) (v'' : A) :=
f (c_cons f v'') v'.
Fixpoint list_correspodence (A : Type) (v' : A) (z : A -> A -> A) (xs : list func v'):=
let fix curry_list {y : A} {z' : A -> A -> A} (l : list z' y) :=
match l with
|Acons x y => cons x (curry_list y)
|Anil _ _ y => cons y nil
end in (#curry_list _ _ xs) z (let fix minimal_case {y' : A} {functor : A -> A -> A} (a : list functor y') {struct a} :=
match a with
|Acons x y => minimal_case y
|Anil _ x _ => x
end in minimal_case xs).
Theorem z_next_list_coorresp : forall {A} (z : A -> A -> A) (x y' : A) (x' : list z x), z (list_correspodence x') y' = list_correspodence (Acons y' x').
intros.
generalize (Acons y' x').
intros.
unfold list_correspodence.
(*reflexivity should works ?*)
Qed.
z_next_list_coorres is actually a lemma i need to prove a goal in another theory (v'_list x = (list_correspodence x)).
I have been trying with some limited scopes to prove list_correspodence and works well, seems that definitions are equal, but for coq not.
Here list_correspondence is a spurious Fixpoint (i.e., fix) (it makes no recursive calls), and this gets in the way of reduction.
You can force reduction of a fix by destructing its decreasing argument:
destruct x'.
- reflexivity.
- reflexivity.
Or you can avoid using Fixpoint in the first place. Use Definition instead.
You may run into a strange bug here with implicit arguments, which is avoided by adding a type signature (as below), or by not marking implicit the arguments of the local function curry_list:
Definition list_correspodence (A : Type) (v' : A) (func : A -> A -> A) (xs : list func v')
: A :=
(* ^ add this *)
I defined a recursive function for all subsets of nat_list in coq as
Fixpoint subsets (a: list nat) : (list (list nat)) :=
match a with
|[] => [[]]
|h::t => subsets t ++ map (app [h]) (subsets t)
end.
I am trying to prove that
forall (a:list nat), In [] (subsets a).
I tried to induct on a. The base-case was straight forward. However in the induction case i tried to use the in-built theorem in_app_or.
Unable to unify "In ?M1396 ?M1394 \/ In ?M1396 ?M1395" with
"(fix In (a : list nat) (l : list (list nat)) {struct l} : Prop :=
match l with
| [] => False
| b :: m => b = a \/ In a m
end)
[] (subsets t ++ map (fun m : list nat => h :: m) (subsets t))".
How do I prove such a theorem or get around such an issue?
The problem with in_app_or is that is has the following type:
forall (A : Type) (l m : list A) (a : A),
In a (l ++ m) -> In a l \/ In a m
and application of lemmas to the goal works "backwards": Coq matches the consequent B of the implication A -> B with the goal, and if they can be unified, you are left with a new goal: you need to prove a (stronger) statement A. And in your case the A and B are in the wrong order (swapped), so you need to apply in_or_app instead:
in_or_app : forall (A : Type) (l m : list A) (a : A),
In a l \/ In a m -> In a (l ++ m)
This is how your goal can be proved using in_or_app:
Goal forall (a:list nat), In [] (subsets a).
intros.
induction a; simpl; auto.
apply in_or_app; auto.
Qed.