Why does coq's typechecker reject my map definition? - coq

I try to experiment with list's definition.
For example let's see this definition:
Inductive list1 : Type -> Type := nil1 : forall (A : Type), list1 A
| cons1 : forall (A : Type), A -> list1 A -> list1 A.
You might think that the definition above is equivalent to this:
Inductive list0 (A : Type) : Type := nil0 : list0 A
| cons0 : A -> list0 A -> list0 A.
Why this map:
Fixpoint map0 {A : Type} {B : Type} (f : A -> B) (xs : list0 A) : list0 B :=
match xs with
nil0 _ => nil0 B
| cons0 _ v ys => cons0 B (f v) (map0 f ys)
end.
accepted, but this one is not:
Fail Fixpoint map1 {A : Type} {B : Type} (f : A -> B) (xs : list1 A) :=
match xs with
nil1 _ => nil1 B
| cons1 _ v ys => cons1 B (f v) (map1 f ys)
end.
?

This is indeed a confusing aspect of datatype definitions. The problem is that list1 is not equivalent to list0, because of how indices and parameters are treated in these definitions. In Coq jargon, an "index" means an argument declared to the right of the colon, as in list1. A "parameter", by contrast, is an argument declared to the left of the colon, as A in list0.
When you use an index, the return type of match expressions must be generic with respect to the index. This can be seen in the type of list1_rec, a combinator for writing recursive definitions on lists:
Check list1_rec.
list1_rec
: forall P : forall T : Type, list1 T -> Set,
(forall A : Type, P A (nil1 A)) ->
(forall (A : Type) (a : A) (l : list1 A), P A l -> P A (cons1 A a l)) ->
forall (T : Type) (l : list1 T), P T l
This type says that given a generic type P indexed by lists and an element l : list1 A, you can produce a result of type P A l by telling Coq what to return on nil1 and cons1. However, the type of the cons1 branch (the third argument of list1) says that the branch must work not only for the A that appears in the type of l, but also for all other types A'. Compare this to the type of list0_rec:
Check list0_rec.
list0_rec
: forall (A : Type) (P : list0 A -> Set),
P (nil0 A) ->
(forall (a : A) (l : list0 A), P l -> P (cons0 A a l)) ->
forall l : list0 A, P l
The branch of cons0 does not have the forall A bit, which means that the branch only has to work for the type A in l : list0 A.
This makes a difference when writing a function such as map. In map0, we are allowed to apply f : A -> B because we know that the argument of cons0 has type A. In map1, the argument of cons1 has a different generic type A', leading to this error message:
Fail Fixpoint map1 {A : Type} {B : Type} (f : A -> B) (xs : list1 A) :=
match xs with
nil1 A' => nil1 B
| cons1 A' v ys => cons1 B (f v) (map1 f ys)
end.
(* The term "v" has type "A'" while it is expected to have type "A". *)

To be complete, you can define function map over list1 :
Fixpoint map1 {A : Type} {B : Type} (f : A -> B) (xs : list1 A) :=
match xs with
| nil1 A' => fun _ => nil1 B
| cons1 A' v ys => fun f => cons1 B (f v) (map1 f ys)
end f.
This is an example of the so-called convoy pattern. Usually, one needs to add a return clause to the match construct so that it typechecks, but here Coq is smart enough to infer it.
However, I certainly discourage using this definition of lists as it will be cumbersome to use in similar cases.

Related

Can one prove an equivalent to Forall_inv for heterogeneous lists in Coq?

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).

Transform casual list into dependently typed list in Coq

I have following definition of list in Coq:
Variable A : Set.
Variable P : A -> Prop.
Hypothesis P_dec : forall x, {P x}+{~(P x)}.
Inductive plist : nat -> Set :=
pnil : plist O
| pcons : A -> forall n, plist n -> plist n
| pconsp : forall (a:A) n, plist n -> P a -> plist (S n)
.
It describes "list of elements of type A where at least n of them fulfill predicate P".
My task is to create function that will convert casual list into plist (with maximum possible n). My attempt was to first count all elements that match P and then set the output type according to the result:
Fixpoint pcount (l : list A) : nat :=
match l with
| nil => O
| h::t => if P_dec h then S(pcount t) else pcount t
end.
Fixpoint plistIn (l : list A) : (plist (pcount l)) :=
match l with
| nil => pnil
| h::t => match P_dec h with
| left proof => pconsp h _ (plistIn t) proof
| right _ => pcons h _ (plistIn t)
end
end.
However, I get an error in the line with left proof:
Error:
In environment
A : Set
P : A -> Prop
P_dec : forall x : A, {P x} + {~ P x}
plistIn : forall l : list A, plist (pcount l)
l : list A
h : A
t : list A
proof : P h
The term "pconsp h (pcount t) (plistIn t) proof" has type
"plist (S (pcount t))" while it is expected to have type
"plist (pcount (h :: t))".
The problem is that Coq cannot see that S (pcount t) equals pcount (h :: t) knowing that P h, which was already proven. I cannot let Coq know this truth.
How to define this function correctly? Is it even possible to do so?
You can use dependent pattern-matching, as the result type plist (pcount (h :: t)) depends on whether P_dec h is left or right.
Below, the keyword as introduces a new variable p, and return tells the type of the whole match expression, parameterized by p.
Fixpoint plistIn (l : list A) : (plist (pcount l)) :=
match l with
| nil => pnil
| h::t => match P_dec h as p return plist (if p then _ else _) with
| left proof => pconsp h (pcount t) (plistIn t) proof
| right _ => pcons h _ (plistIn t)
end
end.
The type plist (if p then _ else _) must be equal to plist (pcount (h :: t)) when substituting p := P_dec h. Then in each branch, say left proof, you need to produce plist (if left proof then _ else _) (which reduces to the left branch).
It's a bit magical that Coq can infer what goes in the underscores here, but to be safe you can always spell it out: if p then S (pcount t) else pcount t (which is meant to exactly match the definition of pcount).

Coq doesn't recognize equality of dependent list

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 *)

Proving theorems about inductive types using _ind; App rule

Variables A B : Prop.
Theorem proj1 : A /\ B -> A.
In order to learn, I'm trying to prove this theorem by explicitly writing down a proof term using and_ind.
I would assume the correct proof term is
fun (H : A /\ B) => and_ind A B A (fun a _ => a) H
But this raises an error, and instead the correct term is
fun (H : A /\ B) => and_ind (fun a _ => a) H
I don't understand this. The definition of and_ind is
and_ind =
fun (A B P : Prop) (f : A -> B -> P) (a : A /\ B) => match a with
| conj x x0 => f x x0
end
: forall A B P : Prop, (A -> B -> P) -> A /\ B -> P
How can I see from that that the parameters (A B P : Prop) have to be omitted?
The "App" rule
from the Reference Manual seems to state clearly that quantified variables have to be explicitly "instantiated" using the function application syntax that I tried.
In Coq, you can declare some arguments of a function as implicit. When you call the function, you don't supply values for the implicit arguments; Coq automatically tries to infer suitable values, based on other information available during type checking. The A, B and P arguments of and_ind are all declared as implicit, and can be inferred from the type of the H argument and the result type of the function argument.
You can see what arguments are considered implicit with the About command:
About and_ind.
(* and_ind : forall A B P : Prop, (A -> B -> P) -> A /\ B -> P *)
(* Arguments A, B, P are implicit *)
(* Argument scopes are [type_scope type_scope type_scope function_scope _] *)
(* and_ind is transparent *)
(* Expands to: Constant Coq.Init.Logic.and_ind *)
You can turn off implicit arguments with an individual call with an # sign:
Check fun A B H => #and_ind A B A (fun a _ => a) H.
(* fun (A B : Prop) (H : A /\ B) => and_ind (fun (a : A) (_ : B) => a) H *)
(* : forall A B : Prop, A /\ B -> A *)
(Notice that Coq automatically omits implicit arguments when printing a term as well.)
The Coq manual has more information on that subject.

When is the first input to `list_rec` not a constant function?

The list_rec function has the type:
list_rec
: forall (A : Type) (P : list A -> Set),
P nil ->
(forall (a : A) (l : list A), P l -> P (a :: l)%list) ->
forall l : list A, P l
In all of the examples I've come up with, P is just a constant function that ignores the input list and returns the same type no matter what. For example, P might be fun _ : list A => nat or fun _ : list A => list B. What are some use cases for making the output of P dependent on the input? Why is the type of P list A -> Set instead of just Set?
We can, for example, use list_rec with a non-constant P function to implement a function that converts a list to a vector (a length-indexed list).
Require List Vector.
Import List.ListNotations Vector.VectorNotations.
Set Implicit Arguments.
Section VecExample.
Variable A : Set.
Definition P (xs : list A) : Set := Vector.t A (length xs).
Definition list_to_vector : forall xs : list A, Vector.t A (length xs) :=
list_rec P [] (fun x _ vtail => x :: vtail).
End VecExample.
You can compare it with the standard definition of the Vector.of_list function, which does exactly the same (t means Vector.t in the following code), using explicit recursion instead of hiding it behind a recursion principle:
Fixpoint of_list {A} (l : list A) : t A (length l) :=
match l as l' return t A (length l') with
|Datatypes.nil => []
|(h :: tail)%list => (h :: (of_list tail))
end.
A simple test:
Eval compute in list_to_vector [1;2;3].
Eval compute in Vector.of_list [1;2;3].
Both function calls return the same result:
= [1; 2; 3]
: Vector.t nat (length [1; 2; 3])
Try to prove s ++ [] = s.
[Hint: Define P as fun s => s ++ [] = s.]