Would it be inconsistent to relax Coq's strict positivity checker to not look at type indices of the inductive type being defined? - coq

Writing
Inductive Foo : Type -> Type :=
| foo : Foo Bar
with
Bar := .
gives
Error: Non strictly positive occurrence of "Bar" in "Foo Bar".
I know the standard example of why strict positivity is necessary; if I have
Inductive Fix :=
| fFix : (Fix -> Fix) -> Fix.
with an eliminator
Fix_rect : forall (P : Fix -> Type) (v : forall f, (forall x, P (f x)) -> P (fFix f)) (f : Fix), P f
then I can prove absurdity with
Fix_rect (fun _ => False) (fun f H => H (fFix id)) (fFix id) : False
(Aside: Does anything go wrong if instead the eliminator is
Fix_rect : forall (P : Fix -> Type) (v : forall f, (forall x, P x -> P (f x)) -> P (fFix f)) (f : Fix), P f
?)
However, I don't see a way to make use of occurrences that appear only in indices. Is there a way to derive a similar contradiction if non-strictly-positive occurrences are permitted in type indices?

This doesn't seem to be a positivity issue, contrary to the error message. Rather, since you have mutual indexing, this is an inductive-inductive type (a weird "large" one at that), which Coq doesn't support.
You could try defining non-indexed types, and separate recursively defined "well-formedness" relations which encode correct indexing. E. g.
Inductive PreFoo : Type :=
| foo : PreFoo.
Inductive Bar : Type :=.
Fixpoint FooWf (f : PreFoo) (t : Type) : Prop :=
match f with
| foo => (t = Bar)
end.
Definition Foo (t : Type) := sig (fun f => FooWf f t).
This is analogous to how you might have indexed intrinsic syntaxes for type theories or extrinsic presyntaxes with separate typing relations.

Related

Overcoming the need of having a constructor in the definition of an other constructor

Most probably I'm trying to achieve something flawed, but I'm running into a need to have a constructor in the definition of another constructor.
Silly example:
Inductive silly_type : Type :=
| constr1 : nat -> silly_type
| constr2 : forall (x : silly_type), (exists n : nat, (x = constr1 n)) -> silly_type.
There are two ways how to create elements of silly_type, either with natural number and constr1 or using constr2 and element of silly_type that was created with constr1.
The above definition of silly_type is not valid in coq, but I do not know how to overcome this in my less silly example.
Less silly example:
I'm trying to have an inductive type expr representing typed expressions.
Let's first start with an inductive type representing types:
Inductive type : Type :=
| base_type : nat -> type
| arrow_type : type -> type -> type
| iso_arrow_type : type -> type -> type.
There are some base types indexed with integers, arrow_type representing function between types and iso_arrow_type representing invertible functions between types.
Notation:
Notation "A --> B" := (arrow_type A B) (at level 30, right associativity).
Notation "A <-> B" := (iso_arrow_type A B).
Type for expressions:
Inductive expr : type -> Type :=
| var : forall (X : type) (n : nat), expr X
| eval : forall {X Y : type} (f : expr (X --> Y)) (x : expr X), expr Y
| inv : forall {X Y : type}, expr ((X <-> Y) --> (Y <-> X))
| to_fun : forall {X Y : type}, expr ((X <-> Y) --> (X --> Y))
| to_iso : forall {X Y : type} (f : expr (X --> Y)), (is_invertible f) -> expr (Y --> X).
You can create an indexed variables of any type with var, evaluate a function with eval, invert an invertible function with inv, cast an invertible function to the actual function with to_fun such that you can evaluate it with eval.
The problem is with the last constructor to_iso. Sometimes, I will know that a function(element of X --> Y) is actually invertible and I want some mechanism to cast it to the type X <-> Y.
However, to define is_invertible I think that I need to use eval. This leads me to the problem that the constructor eval needs to be in the definition of the constructor to_iso.
To define is_invertible, we first need to define a notion of equality of expr:
Inductive ExprEq : forall (X : type), X -> X -> Prop :=
| expr_eq_refl : forall {X : type}, forall (x : X), ExprEq X x x
| eq_on_values : forall {X Y : type}, forall (f g : (X --> Y)), (forall (x : X), f[x] == g[x]) -> f == g
where
"x == y" := (ExprEq _ x y) and "f [ x ]" := (eval f x) and "x =/= y" := (not (ExprEq _ x y)).
Thus, we have standard reflexivity x == x and equality of functions f==g can be decided by equality on all elements f[x]==g[x].
Now, we are ready to define is_invertible:
Definition is_invertible {X Y : type} (f : X --> Y) : Prop := exists g : Y --> X, (forall x, g[f[x]] == x) /\ (forall y, f[g[y]] == y).
This definition of is_invertible is problematic, it is using eval(f[x] := (eval f x)). Furthermore, the problem is a bit more complicated. We need to define the type ExprEq that already uses eval to define its constructors.
Constrain: keep expr decidable
What I really want to preserve is that the equality(=) of expr is decidable, i.e. being able to prove
Lemma eq_expr_dec {X : type} (x y : type) : {x=y} + {x<>y}.
I really do not care about decidability of the defined equality ==, but decidability of = is important for me.
You can use dependent types to index your constructors. For example
Inductive silly_type : nat -> Type :=
| constr1 : nat -> silly_type 0
| constr2 : silly_type 0 -> silly_type 1.
So you can only use values produced by constr1 in constr2. This approach should work in general to distinguish values created with different constructors.

Induction on a datatype with non-uniform type parameters produces ill-typed terms

I'm working towards formalising Free Selective Applicative Functors in Coq, but struggling with proofs by induction for inductive data types with non-uniform type parameters.
Let me give a bit of an introduction on the datatype I'm dealing with.
In Haskell, we encode Free Selective Functors as a GADT:
data Select f a where
Pure :: a -> Select f a
Select :: Select f (Either a b) -> f (a -> b) -> Select f b
The crucial thing here is the existential type variable b in the second data constructor.
We can translate this definition to Coq:
Inductive Select (F : Type -> Type) (A : Set) : Set :=
Pure : A -> Select F A
| MkSelect : forall (B : Set), Select F (B + A) -> F (B -> A) -> Select F A.
As a side note, I use the -impredicative-set option to encode it.
Coq generates the following induction principle for this datatype:
Select_ind :
forall (F : Type -> Type) (P : forall A : Set, Select F A -> Prop),
(forall (A : Set) (a : A), P A (Pure a)) ->
(forall (A B : Set) (s : Select F (B + A)), P (B + A)%type s ->
forall f0 : F (B -> A), P A (MkSelect s f0)) ->
forall (A : Set) (s : Select F A), P A s
Here, the interesting bit is the predicate P : forall A : Set, Select F A -> Prop which is parametrised not only in the expression, but also in the expressions type parameter. As I understand, the induction principle has this particular form because of the first argument of the MkSelect constructor of type Select F (B + A).
Now, I would like to prove statements like the third Applicative law for the defined datatype:
Theorem Select_Applicative_law3
`{FunctorLaws F} :
forall (A B : Set) (u : Select F (A -> B)) (y : A),
u <*> pure y = pure (fun f => f y) <*> u.
Which involve values of type Select F (A -> B), i.e. expressions containing functions. However,
calling induction on variables of such types produces ill-typed terms. Consider an oversimplified example of an equality that can be trivially proved by reflexivity, but can't be proved using induction:
Lemma Select_induction_fail `{Functor F} :
forall (A B : Set) (a : A) (x : Select F (A -> B)),
Select_map (fun f => f a) x = Select_map (fun f => f a) x.
Proof.
induction x.
Coq complains with the error:
Error: Abstracting over the terms "P" and "x" leads to a term
fun (P0 : Set) (x0 : Select F P0) =>
Select_map (fun f : P0 => f a) x0 = Select_map (fun f : P0 => f a) x0
which is ill-typed.
Reason is: Illegal application (Non-functional construction):
The expression "f" of type "P0" cannot be applied to the term
"a" : "A"
Here, Coq can't construct the predicate abstracted over the type variable because the reversed function application from the statement becomes ill-typed.
My question is, how do I use induction on my datatype? I can't see a way how to modify the induction principle in such a way so the predicate would not abstract the type. I tried to use dependent induction, but it has been producing inductive hypothesis constrained by equalities similar to (A -> B -> C) = (X + (A -> B -> C)) which I think would not be possible to instantiate.
Please see the complete example on GitHub: https://github.com/tuura/selective-theory-coq/blob/impredicative-set/src/Control/Selective/RigidImpredSetMinimal.v
UPDATE:
Following the discussio in the gist I have tried to carry out proofs by induction on depth of expression. Unfortunately, this path was not very fruitful since the induction hypothesis I get in theorems similar to Select_Applicative_law3 appear to be unusable. I will leave this problem for now and will give it a try later.
Li-yao, many thanks again for helping me to improve my understanding!
Proofs by induction are motivated by recursive definitions. So to know what to apply induction to, look for Fixpoints.
Your Fixpoints most likely work on terms indexed by single type variables Select F A, that's exactly where you want to use induction, not at the toplevel of the goal.
A Fixpoint on terms indexed by function types A -> B is useless since no subterms of any Select term are indexed by function types. For the same reason, induction is useless on such terms.
Here I think the strong type discipline actually forces you to work everything out on paper before trying to do anything in Coq (which is a good thing in my opinion). Try to do the proof on paper, without even worrying about types; explicitly write down the predicate(s) you want to prove by induction. Here's a template to see what I mean:
By induction on u, we will show
u <*> pure x = pure (fun f => f x) <*> u
(* Dummy induction predicate for the sake of example. *)
(* Find the right one. *)
(* It may use quantifiers... *)
Base case (set u = Pure f). Prove:
Pure f <*> pure x = pure (fun f => f x) <*> Pure f
Induction step (set u = MkSelect v h). Prove:
MkSelect v h <*> pure x = pure (fun f => f x) <*> MkSelect v h
assuming the induction hypothesis for the subterm v (set u = v):
v <*> pure x = pure (fun f => f x) <*> v
Notice in particular that the last equation is ill-typed, but you can still run along with it to do equational reasoning. Regardless, it will likely turn out that there is no way to apply that hypothesis after simplifying the goal.
If you really need to use Coq to do some exploration, there is a trick, consisting in erasing the problematic type parameter (and all terms that depend on it). Depending on your familiarity with Coq, this tip may turn out to be more confusing than anything. So be careful.
The terms will still have the same recursive structure. Keep in mind that the proof should also follow the same structure, because the point is to add more types on top afterwards, so you should avoid shortcuts that rely on the lack of types if you can.
(* Replace all A and B by unit. *)
Inductive Select_ (F : unit -> Type) : Set :=
| Pure_ : unit -> Select_ F
| MkSelect_ : Select_ F -> F tt -> Select_ F
.
Arguments Pure_ {F}.
Arguments MkSelect_ {F}.
(* Example translating Select_map. The Functor f constraint gets replaced with a dummy function argument. *)
(* forall A B, (A -> B) -> (F A -> F B) *)
Fixpoint Select_map_ {F : unit -> Type} (fmap : forall t, unit -> (F t -> F t)) (f : unit -> unit) (v : Select_ F) : Select_ F :=
match v with
| Pure_ a => Pure_ (f a)
| MkSelect_ w h => MkSelect_ (Select_map_ fmap f w) (fmap _ tt h)
end.
With that, you can try to prove this trimmed down version of the functor laws for example:
Select_map_ fmap f (Select_map_ fmap g v) = Select_map_ fmap (fun x => f (g x)) v
(* Original theorem:
Select_map f (Select_map g v) = Select_map (fun x => f (g x)) v
*)
The point is that removing the parameter avoids the associated typing problems, so you can try to use induction naively to see how things (don't) work out.

Have problem with unable to use destruct tatic in a Definition

I am working with a definition in coq which need to yield something from a Theorem, but cannot destruct in the definition.
Theorem sp : forall (X : Type) (T : X -> Prop)..... , exists (a : X), T a.
Definition yield_sp : (X : Type) (T : X -> Prop) (H : sp X T .....)..... : X.
When I try to destruct H, coq warns that
Case analysis on sort Type is not allowed for inductive definition ex.
I would like to know the reason for it, and further, how to use definition to yield an element from an "exists" proposition.
You cannot extract the witness out of an existence proof. There are a few options:
Change the statement of the proof to {x : T | P x}, which behaves more-or-less like the existential quantifier, but supports a projection function proj1_sig : {x : T | P x} -> T.
Assume a choice axiom, as in https://coq.inria.fr/library/Coq.Logic.ClassicalChoice.html
If you are quantifying over a countable type and your proposition is decidable, you can use the trick in this question to extract the witness.

Specifying polarity in a module type

The following inductive definition of U is accepted by Coq because it can see that the occurrences of U in M.T U -> U are strictly positive.
Module M.
Definition T (A : Type) : Type := unit -> A.
End M.
Module N.
Inductive U : Type :=
| c : M.T U -> U.
End N.
On the other hand, the following inductive definition of U is not accepted by Coq because, depending on the definition of M.T, it might have non-strictly positive occurrences.
Module Type S.
Parameter T : Type -> Type.
End S.
Module N (M : S).
Fail Inductive U : Type :=
| c : M.T U -> U.
End N.
How can I specify in the signature S that the parameter of T should only have strictly negative occurrences? Thus preventing any non-strictly positive occurrences of U in its definition.
This U type can be seen as the least fixed point of M.T. Another common encoding is
Definition Mu (T : Type -> Type) := forall A, (T A -> A) -> A.
Definition U := Mu M.T.
Provided that T is a functor (which strict positivity would imply, maybe?):
Parameter map : forall A B, (A -> B) -> T A -> T B. (* in module M *)
we have a constructor and destructor:
Definition c : M.T U -> U := fun x A f =>
f (M.map _ _ (fun y => y _ f) x).
Definition d : U -> M.T U := fun y => y _ (fun x => M.map _ _ c x).
Showing they are inverses requires parametricity, so there is no direct way to prove it. If you don't want to axiomatize it, you can probably enrich T and U to carry evidence of parametricity.
Essentially, the requirement above that T be a functor is a semantic replacement/approximation of the strict positivity condition, which is syntactic.
It is also possible to switch off positivity checking with this new plugin:
https://github.com/SimonBoulier/TypingFlags

Different induction principles for Prop and Type

I noticed that Coq synthesizes different induction principles on equality for Prop and Type. Does anybody have an explanation for that?
Equality is defined as
Inductive eq (A : Type) (x : A) : A -> Prop := eq_refl : x = x
And the associated induction principle has the following type:
eq_ind
: forall (A : Type) (x : A) (P : A -> Prop),
P x -> forall y : A, x = y -> P y
Now let's define a Type pendant of eq:
Inductive eqT {A:Type}(x:A):A->Type:= eqT_refl: eqT x x.
The automatically generated induction principle is
eqT_ind
: forall (A : Type) (x : A) (P : forall a : A, eqT x a -> Prop),
P x (eqT_refl x) -> forall (y : A) (e : eqT x y), P y e
Note: I'm going to use _rect principles everywhere instead of _ind, since _ind principles are usually implemented via the _rect ones.
Type of eqT_rect
Let's take a look at the predicate P.
When dealing with inductive families, the number of arguments of P is equal to the number of non-parametric arguments (indices) + 1.
Let me give some examples (they can be easily skipped).
Natural numbers don't have parameters at all:
Inductive nat : Set := O : nat | S : nat -> nat.
So, the predicate P will be of type nat -> Type.
Lists have one parametric argument (A):
Inductive list (A : Type) : Type :=
nil : list A | cons : A -> list A -> list A.
Again, P has only one argument: P : list A -> Type.
Vectors are a different:
Inductive vec (A : Type) : nat -> Type :=
nil : vec A 0
| cons : A -> forall n : nat, vec A n -> vec A (S n).
P has 2 arguments, because n in vec A n is a non-parameteric argument:
P : forall n : nat, vec A n -> Type
The above explains eqT_rect (and, of course, eqT_ind as a consequence), since the argument after (x : A) is non-parametric, P has 2 arguments:
P : forall a : A, eqT x a -> Type
which justifies the overall type for eqT_rect:
eqT_rect
: forall (A : Type) (x : A) (P : forall a : A, eqT x a -> Type),
P x (eqT_refl x) -> forall (y : A) (e : eqT x y), P y e
The induction principle obtained in this way is called a maximal induction principle.
Type of eq_rect
The generated induction principles for inductive predicates (such as eq) are simplified to express proof irrelevance (the term for this is simplified induction principle).
When defining a predicate P, Coq simply drops the last argument of the predicate (which is the type being defined, and it lives in Prop). That's why the predicate used in eq_rect is unary. This fact shapes the type of eq_rect:
eq_rect :
forall (A : Type) (x : A) (P : A -> Type),
P x -> forall y : A, x = y -> P y
How to generate maximal induction principle
We can also make Coq generate non-simplified induction principle for eq:
Scheme eq_rect_max := Induction for eq Sort Type.
The resulting type is
eq_rect_max :
forall (A : Type) (x : A) (P : forall a : A, x = a -> Type),
P x eq_refl -> forall (y : A) (e : x = y), P y e
and it has the same structure as eqT_rect.
References
For more detailed explanation see sect. 14.1.3 ... 14.1.6 of the book "Interactive Theorem Proving and Program Development (Coq'Art: The Calculus of Inductive Constructions)" by Bertot and Castéran (2004).