I have a type defined as
Inductive bits : nat -> Set :=
| bitsNil : bits 0
| bitsCons : forall {l}, bool -> bits l -> bits (S l).
and I'm trying to prove:
Lemma emptyIsAlwaysNil : forall {a: bits 0}, a = bitsNil.
After intros, I've tried constructor 1, case a, intuition, to no avail. case a seems like the closest, but it gets an error:
Abstracting over the terms "0" and "a" leads to a term
fun (n : nat) (a0 : bits n) => a0 = bitsNil
which is ill-typed.
Reason is: Illegal application:
The term "#eq" of type "forall A : Type, A -> A -> Prop"
cannot be applied to the terms
"bits n" : "Set"
"a0" : "bits n"
"bitsNil" : "bits 0"
The 3rd term has type "bits 0" which should be coercible to
"bits n".
It sounds like it can't determine whether a bit-vector of an arbitrary length is equal to one of zero-length, because they're different at the type level. Is that correct?
Yes, you're basically correct: specifically, what isn't type checking is Coq's attempt to construct a match on a:bits 0 (which is what case does): the bitsCons case has an ill-typed conclusion.
Here's an axiom-free proof. The key idea is to manually generalize the statement to any n = 0 (I couldn't figure out how to do this with tactics; they all trip up on the dependency). The equality proof then makes the conclusion type check regardless of what n is, and we can dismiss the bitsCons case because we'll have n = S n'. In the more difficult bitsNil case, we make use of eq_rect_eq_dec, which is a consequence of Axiom K but is provable when the type index (nat, in this case) has decidable equality. See the Coq standard library documentation for some other things you can do without axioms with decidable equality.
Require PeanoNat.
Require Import Eqdep_dec.
Import EqNotations.
Inductive bits : nat -> Set :=
| bitsNil : bits 0
| bitsCons : forall {l}, bool -> bits l -> bits (S l).
Lemma emptyIsAlwaysNil_general :
forall n (H: n = 0) {a: bits n},
rew [bits] H in a = bitsNil.
Proof.
intros.
induction a; simpl.
(* bitsNil *)
rewrite <- eq_rect_eq_dec; auto.
apply PeanoNat.Nat.eq_dec.
(* bitsCons - derive a contradiction *)
exfalso; discriminate H.
Qed.
Lemma emptyIsAlwaysNil : forall {a: bits 0},
a = bitsNil.
Proof.
intros.
change a with (rew [bits] eq_refl in a).
apply emptyIsAlwaysNil_general.
Qed.
You don't need the rew H in x notation from EqNotations (it just wraps eq_rect, the equality recursion principle), but I find it makes things much more readable.
However, you can prove this theorem more simply if you're willing to use an axiom, specifically JMeq_eq (see CPDT's equality chapter for more details), since then you can use dependent induction or dependent destruction:
Require Import Program.Equality.
Inductive bits : nat -> Set :=
| bitsNil : bits 0
| bitsCons : forall {l}, bool -> bits l -> bits (S l).
Lemma emptyIsAlwaysNil :
forall {a: bits 0}, a = bitsNil.
Proof.
intros.
dependent destruction a; reflexivity.
Qed.
Print Assumptions emptyIsAlwaysNil.
(* Axioms:
JMeq_eq : forall (A : Type) (x y : A), x ~= y -> x = y *)
Here is a simple proof (borrowed from this Coq Club thread):
Definition emptyIsAlwaysNil {a: bits 0} : a = bitsNil :=
match a with bitsNil => eq_refl end.
Opaque emptyIsAlwaysNil.
Here is what Coq builds under the hood:
Print emptyIsAlwaysNil.
emptyIsAlwaysNil =
fun a : bits 0 =>
match
a as a0 in (bits n)
return
(match n as x return (bits x -> Type) with
| 0 => fun a1 : bits 0 => a1 = bitsNil
| S n0 => fun _ : bits (S n0) => IDProp
end a0)
with
| bitsNil => eq_refl
| bitsCons _ _ => idProp
end
: forall a : bits 0, a = bitsNil
Related
I was going through the Coq book from the maths perspective. I was trying to define a dependently typed function that returned a length list with n trues depending on the number trues we want.
Coq complains that things don't have the right type but when I see it if it were to unfold my definitions when doing the type comparison it should have worked but it doesn't. Why?
Code:
Module playing_with_types2.
Inductive Vector {A: Type} : nat -> Type :=
| vnil: Vector 0
| vcons: forall n : nat, A -> Vector n -> Vector (S n).
Definition t {A: Type} (n : nat) : Type :=
match n with
| 0 => #Vector A 0
| S n' => #Vector A (S n')
end.
Check t. (* nat -> Type *)
Check #t. (* Type -> nat -> Type *)
(* meant to mimic Definition g : forall n: nat, t n. *)
Fixpoint g (n : nat) : t n :=
match n with
| 0 => vnil
| S n' => vcons n' true (g n')
end.
End playing_with_types2.
Coq's error:
In environment
g : forall n : nat, t n
n : nat
The term "vnil" has type "Vector 0" while it is expected to have type
"t ?n#{n1:=0}".
Not in proof mode.
i.e. t ?n#{n1:=0} is Vector 0...no?
In this case, it looks like Coq does not manage to infer the return type of the match expression, so the best thing to do is to give it explicitly:
Fixpoint g (n : nat) : t n :=
match n return t n with
| 0 => vnil
| S n' => vcons n' true (g n')
end.
Note the added return clause.
Then the real error message appears:
In environment
g : forall n : nat, t n
n : nat
n' : nat
The term "g n'" has type "t n'" while it is expected to have type "Vector n'".
And this time it is true that in general t n' is not the same as Vector n' because t n' is stuck (it does not know yet whether n' is 0 or some S n'').
data _∈_ {X : Set} (x : X) : (xs : List X) → Set where
here! : {xs : List X} → x ∈ x ∷ xs
there : {xs : List X} {y : X} (pr : x ∈ xs) → x ∈ y ∷ xs
remove : {X : Set} {x : X} (xs : List X) (pr : x ∈ xs) → List X
remove (_ ∷ xs) here! = xs
remove (y ∷ xs) (there pr) = y ∷ remove xs pr
I am trying to translate the above definition from Agda to Coq and am running into difficulties.
Inductive Any {A : Type} (P : A -> Type) : list A -> Prop :=
| here : forall {x : A} {xs : list A}, P x -> Any P (x :: xs)
| there : forall {x : A} {xs : list A}, Any P xs -> Any P (x :: xs).
Definition In' {A : Type} (x : A) xs := Any (fun x' => x = x') xs.
Fixpoint remove {A : Type} {x : A} {l : list A} (pr : In' x l) : list A :=
match l, pr with
| [], _ => []
| _ :: ls, here _ _ => ls
| x :: ls, there _ pr => x :: remove pr
end.
Incorrect elimination of "pr0" in the inductive type "#Any":
the return type has sort "Type" while it should be "Prop".
Elimination of an inductive object of sort Prop
is not allowed on a predicate in sort Type
because proofs can be eliminated only to build proofs.
In addition to this error, if I leave the [] case out Coq is asks me to provide it despite it being absurd.
Up to this point, I've thought that Agda and Coq were the same languages with a different front end, but now I am starting to think they are different under the hood. Is there a way to replicate the remove function in Coq and if not, what alternative would you recommend?
Edit: I also want to keep the proof between In and In'. Originally I made In' a Type rather than a Prop, but that made the following proof fail with a type error.
Fixpoint In {A : Type} (x : A) (l : list A) : Prop :=
match l with
| [] ⇒ False
| x' :: l' ⇒ x' = x ∨ In x l'
end.
Theorem In_iff_In' :
forall {A : Type} (x : A) (l : list A),
In x l <-> In' x l.
Proof.
intros.
split.
- intros.
induction l.
+ inversion H.
+ simpl in H.
destruct H; subst.
* apply here. reflexivity.
* apply there. apply IHl. assumption.
- intros.
induction H.
+ left. subst. reflexivity.
+ right. assumption.
Qed.
In environment
A : Type
x : A
l : list A
The term "In' x l" has type "Type" while it is expected to have type
"Prop" (universe inconsistency).
The In here is from the Logic chapter of SF. I have a solution of the pigeonhole principle in Agda, so I want this bijection in order to convert to the form that the exercise asks.
Edit2:
Theorem remove_lemma :
forall {A} {x} {y} {l : list A} (pr : In' x l) (pr' : In' y l),
x = y \/ In' y (remove pr).
I also outright run into universe inconsistency in this definition even when using Type when defining In'.
You need to use an informative proof of membership. Right now, your Any takes values in Prop, which, due to its limitations on elimination (see the error message you got), is consistent with the axiom forall (P: Prop) (x y: P), x = y. This means that if you have some term that depends on a term whose type is in Prop (as is the case with remove), it has to only use the fact that such a term exists, not what term it is specifically. Generally, you can't use elimination (usually pattern matching) on a Prop to produce anything other than something that's also a Prop.
There are three essentially different proofs of In' 1 [1; 2; 1; 3; 1; 4], and, depending which proof is used, remove p might be [2; 1; 4; 1; 4], [1; 2; 3; 1; 4] or [1; 2; 1; 3; 4]. So the output depends on the specific proof in an essential way.
To fix this, you can simply replace the Prop in Inductive Any {A : Type} (P : A -> Type) : list A -> Prop with Type.1 Now we can eliminate into non-Prop types and your definition of remove works as written.
To answer your edits, I think the biggest issue is that some of your theorems/definitions need In' to be a Prop (because they depend on uninformative proofs) and others need the informative proof.
I think your best bet is to keep In' as a Type, but then prove uninformative versions of the theorems. In the standard libary, in Coq.Init.Logic, there is an inductive type inhabited.
Inductive inhabited (A: Type): Prop :=
| inhabits: A -> inhabited A.
This takes a type and essentially forgets anything specific about its terms, only remembering if it's inhabited or not. I think your theorem and lemma are provable if you simply replace In' x l with inhabited (In' x l). I was able to prove a variant of your theorem whose conclusion is simply In x l <-> inhabited (In' x l). Your proof mostly worked, but I had to use the following simple lemma in one step:
Lemma inhabited_there {A: Type} {P: A -> Type} {x: A} {xs: list A}:
inhabited (Any P xs) -> inhabited (Any P (x :: xs)).
Note: even though inhabited A is basically just a Prop version of A and we have A -> inhabited A, we can't prove inhabited A -> A in general because that would involve choosing an arbitrary element of A.2
I also suggested Set here before, but this doesn't work since the inductive type depends on A, which is in Type.
In fact, I believe that the proof assistant Lean uses something very similar to this for its axiom of choice.
I'm learning Coq and I've stumbled upon an exercise asking to create functions for the option type to/from bool and nat (i.e., bool to/from option X, nat to option nat), and then prove they commute. I can easily prove by induction on bool/nat, but I can't seem to make it work for the option type. The main problem in the bool question that I ran into is that, at some point, the goal is to prove that:
a : nat_iter 1 option Empty_set
============================
Some None = Some a
however, I don't know tell it the only possibility for nat_iter 1 option Empty_set is to be None (I have a lemma proving that, but can't rewrite a).
With the nat one, I don't think there is a bijection between nat and option nat, since I cannot prove that, given fromNat (toNat x) = x, Some 0 = None. Maybe there's a way to define toNat that makes this work.
Definition fromBool (b : bool) : fin 2 :=
match b with
| true => Some None
| false => None
end.
Definition toBool (x : fin 2) : bool :=
match x with
| None => false
| Some _ => true
end.
Lemma bool_fin b :
toBool (fromBool b) = b.
Proof. induction b ; reflexivity. Qed.
Lemma fin_bool x :
fromBool (toBool x) = x.
Proof. induction x ; simpl. Abort.
Definition fromNat (n : nat) : option nat :=
match n with
| 0 => None
| S n => Some (S n)
end.
Definition toNat (n : option nat) : nat :=
match n with
| None => 0
| Some x => x
end.
Lemma nat_option x :
toNat (fromNat x) = x.
Proof. induction x ; reflexivity. Qed.
Lemma option_nat x :
fromNat (toNat x) = x.
Proof. induction x. Abort.
Thanks.
I have a list with a known value and want to induct on it, keeping track of what the original list was, and referring to it by element. That is, I need to refer to it by l[i] with varying i instead of just having (a :: l).
I tried to make an induction principle to allow me to do that. Here is a program with all of the unnecessary Theorems replaced with Admitted, using a simplified example. The objective is to prove allLE_countDown using countDown_nth, and have list_nth_rect in a convenient form. (The theorem is easy to prove directly without any of those.)
Require Import Arith.
Require Import List.
Definition countDown1 := fix f a i := match i with
| 0 => nil
| S i0 => (a + i0) :: f a i0
end.
(* countDown from a number to another, excluding greatest. *)
Definition countDown a b := countDown1 b (a - b).
Theorem countDown_nth a b i d (boundi : i < length (countDown a b))
: nth i (countDown a b) d = a - i - 1.
Admitted.
Definition allLE := fix f l m := match l with
| nil => true
| a :: l0 => if Nat.leb a m then f l0 m else false
end.
Definition drop {A} := fix f (l : list A) n := match n with
| 0 => l
| S a => match l with
| nil => nil
| _ :: l2 => f l2 a
end
end.
Theorem list_nth_rect_aux {A : Type} (P : list A -> list A -> nat -> Type)
(Pnil : forall l, P l nil (length l))
(Pcons : forall i s l d (boundi : i < length l), P l s (S i) -> P l ((nth i l d) :: s) i)
l s i (size : length l = i + length s) (sub : s = drop l i) : P l s i.
Admitted.
Theorem list_nth_rect {A : Type} (P : list A -> list A -> nat -> Type)
(Pnil : forall l, P l nil (length l))
(Pcons : forall i s l d (boundi : i < length l), P l s (S i) -> P l ((nth i l d) :: s) i)
l s (leqs : l = s): P l s 0.
Admitted.
Theorem allLE_countDown a b : allLE (countDown a b) a = true.
remember (countDown a b) as l.
refine (list_nth_rect (fun l s _ => l = countDown a b -> allLE s a = true) _ _ l l eq_refl Heql);
intros; subst; [ apply eq_refl | ].
rewrite countDown_nth; [ | apply boundi ].
pose proof (Nat.le_sub_l a (i + 1)).
rewrite Nat.sub_add_distr in H0.
apply leb_correct in H0.
simpl; rewrite H0; clear H0.
apply (H eq_refl).
Qed.
So, I have list_nth_rect and was able to use it with refine to prove the theorem by referring to the nth element, as desired. However, I had to construct the Proposition P myself. Normally, you'd like to use induction.
This requires distinguishing which elements are the original list l vs. the sublist s that is inducted on. So, I can use remember.
Theorem allLE_countDown a b : allLE (countDown a b) a = true.
remember (countDown a b) as s.
remember s as l.
rewrite Heql.
This puts me at
a, b : nat
s, l : list nat
Heql : l = s
Heqs : l = countDown a b
============================
allLE s a = true
However, I can't seem to pass the equality as I just did above. When I try
induction l, s, Heql using list_nth_rect.
I get the error
Error: Abstracting over the terms "l", "s" and "0" leads to a term
fun (l0 : list ?X133#{__:=a; __:=b; __:=s; __:=l; __:=Heql; __:=Heqs})
(s0 : list ?X133#{__:=a; __:=b; __:=s; __:=l0; __:=Heql; __:=Heqs})
(_ : nat) =>
(fun (l1 l2 : list nat) (_ : l1 = l2) =>
l1 = countDown a b -> allLE l2 a = true) l0 s0 Heql
which is ill-typed.
Reason is: Illegal application:
The term
"fun (l l0 : list nat) (_ : l = l0) =>
l = countDown a b -> allLE l0 a = true" of type
"forall l l0 : list nat, l = l0 -> Prop"
cannot be applied to the terms
"l0" : "list nat"
"s0" : "list nat"
"Heql" : "l = s"
The 3rd term has type "l = s" which should be coercible to
"l0 = s0".
So, how can I change the induction principle
such that it works with the induction tactic?
It looks like it's getting confused between
the outer variables and the ones inside the
function. But, I don't have a way to talk
about the inner variables that aren't in scope.
It's very strange, since invoking it with
refine works without issues.
I know for match, there's as clauses, but
I can't figure out how to apply that here.
Or, is there a way to make list_nth_rect use
P l l 0 and still indicate which variables correspond to l and s?
First, you can prove this result much more easily by reusing more basic ones. Here's a version based on definitions of the ssreflect library:
From mathcomp
Require Import ssreflect ssrfun ssrbool ssrnat eqtype seq.
Definition countDown n m := rev (iota m (n - m)).
Lemma allLE_countDown n m : all (fun k => k <= n) (countDown n m).
Proof.
rewrite /countDown all_rev; apply/allP=> k; rewrite mem_iota.
have [mn|/ltnW] := leqP m n.
by rewrite subnKC //; case/andP => _; apply/leqW.
by rewrite -subn_eq0 => /eqP ->; rewrite addn0 ltnNge andbN.
Qed.
Here, iota n m is the list of m elements that counts starting from n, and all is a generic version of your allLE. Similar functions and results exist in the standard library.
Back to your original question, it is true that sometimes we need to induct on a list while remembering the entire list we started with. I don't know if there is a way to get what you want with the standard induction tactic; I didn't even know that it had a multi-argument variant. When I want to prove P l using this strategy, I usually proceed as follows:
Find a predicate Q : nat -> Prop such that Q (length l) implies P l. Typically, Q n will have the form n <= length l -> R (take n l) (drop n l), where R : list A -> list A -> Prop.
Prove Q n for all n by induction.
I do not know if this answers your question, but induction seems to accept with clauses. Thus, you can write the following.
Theorem allLE_countDown a b : allLE (countDown a b) a = true.
remember (countDown a b) as s.
remember s as l.
rewrite Heql.
induction l, s, Heql using list_nth_rect
with (P:=fun l s _ => l = countDown a b -> allLE s a = true).
But the benefit is quite limited w.r.t. the refine version, since you need to specify manually the predicate.
Now, here is how I would have proved such a result using objects from the standard library.
Require Import List. Import ListNotations.
Require Import Omega.
Definition countDown1 := fix f a i := match i with
| 0 => nil
| S i0 => (a + i0) :: f a i0
end.
(* countDown from a number to another, excluding greatest. *)
Definition countDown a b := countDown1 b (a - b).
Theorem countDown1_nth a i k d (boundi : k < i) :
nth k (countDown1 a i) d = a + i -k - 1.
Proof.
revert k boundi.
induction i; intros.
- inversion boundi.
- simpl. destruct k.
+ omega.
+ rewrite IHi; omega.
Qed.
Lemma countDown1_length a i : length (countDown1 a i) = i.
Proof.
induction i.
- reflexivity.
- simpl. rewrite IHi. reflexivity.
Qed.
Theorem countDown_nth a b i d (boundi : i < length (countDown a b))
: nth i (countDown a b) d = a - i - 1.
Proof.
unfold countDown in *.
rewrite countDown1_length in boundi.
rewrite countDown1_nth.
replace (b+(a-b)) with a by omega. reflexivity. assumption.
Qed.
Theorem allLE_countDown a b : Forall (ge a) (countDown a b).
Proof.
apply Forall_forall. intros.
apply In_nth with (d:=0) in H.
destruct H as (n & H & H0).
rewrite countDown_nth in H0 by assumption. omega.
Qed.
EDIT:
You can state an helper lemma to make an even more concise proof.
Lemma Forall_nth : forall {A} (P:A->Prop) l,
(forall d i, i < length l -> P (nth i l d)) ->
Forall P l.
Proof.
intros. apply Forall_forall.
intros. apply In_nth with (d:=x) in H0.
destruct H0 as (n & H0 & H1).
rewrite <- H1. apply H. assumption.
Qed.
Theorem allLE_countDown a b : Forall (ge a) (countDown a b).
Proof.
apply Forall_nth.
intros. rewrite countDown_nth. omega. assumption.
Qed.
The issue is that, for better or for worse, induction seems to assume that its arguments are independent. The solution, then, is to let induction automatically infer l and s from Heql:
Theorem list_nth_rect {A : Type} {l s : list A} (P : list A -> list A -> nat -> Type)
(Pnil : P l nil (length l))
(Pcons : forall i s d (boundi : i < length l), P l s (S i) -> P l ((nth i l d) :: s) i)
(leqs : l = s): P l s 0.
Admitted.
Theorem allLE_countDown a b : allLE (countDown a b) a = true.
remember (countDown a b) as s.
remember s as l.
rewrite Heql.
induction Heql using list_nth_rect;
intros; subst; [ apply eq_refl | ].
rewrite countDown_nth; [ | apply boundi ].
pose proof (Nat.le_sub_l a (i + 1)).
rewrite Nat.sub_add_distr in H.
apply leb_correct in H.
simpl; rewrite H; clear H.
assumption.
Qed.
I had to change around the type of list_nth_rect a bit; I hope I haven't made it false.
The following code (which is of course not a complete proof) tries to do pattern matching on a dependent product:
Record fail : Set :=
mkFail {
i : nat ;
f : forall x, x < i -> nat
}.
Definition failomat : forall (m : nat) (f : forall x, x < m -> nat), nat.
Proof.
intros.
apply 0.
Qed.
Function fail_hard_omat fl : nat := failomat (i fl) (f fl).
Definition failhard fl : fail_hard_omat fl = 0.
refine ((fun fl =>
match fl with
| mkFail 0 _ => _
| mkFail (S n) _ => _
end) fl).
The error I get when trying to execute this is
Toplevel input, characters 0-125:
Error: Illegal application (Type Error):
The term "mkFail" of type
"forall i : nat, (forall x : nat, x < i -> nat) -> fail"
cannot be applied to the terms
"i" : "nat"
"f0" : "forall x : nat, x < i0 -> nat"
The 2nd term has type "forall x : nat, x < i0 -> nat"
which should be coercible to "forall x : nat, x < i -> nat".
It seems that the substitution somehow does not reach the inner type parameters.
After playing with the Program command I managed to build a refine that might suites you, but I don't understand everything I did. The main idea is to help Coq with the substitution by introducing intermediate equalities that will serve as brige within the substitution
refine ((fun fl =>
match fl as fl0 return (fl0 = fl -> fail_hard_omat fl0 = 0) with
| mkFail n bar =>
match n as n0 return (forall foo: (forall x:nat, x < n0 -> nat),
mkFail n0 foo = fl -> fail_hard_omat (mkFail n0 foo) = 0) with
| O => _
| S p => _
end bar
end (eq_refl fl) ) fl).
Anyway, I don't know what your purpose here is, but I advise never write dependent match "by hand" and rely on Coq's tactics. In your case, if you define your Definition failomat with Defined. instead of Qed, you will be able to unfold it and you won't need dependent matching.
Hope it helps,
V.
Note: both occurences of bar can be replaced by an underscore.
Another, slightly less involved, alternative is to use nat and fail's induction combinators.
Print nat_rect.
Print fail_rect.
Definition failhard : forall fl, fail_hard_omat fl = 0.
Proof.
refine (fail_rect _ _). (* Performs induction (projection) on fl. *)
refine (nat_rect _ _ _). (* Performs induction on fl's first component. *)
Show Proof.