Are Coercions allowed within polymorphic datatypes in coq? - coq

I'm using a lot of pairs with types that would normally be coerced freely. However, the notation doesn't explicitly provide the types for the pairs, even though the context does. The following code provides a simple MWE of the principle:
Coercion nat_to_bool (n : nat) : bool :=
match n with
| 0 => false
| _ => true
end.
Inductive newtype : Type :=
| firstconstr : bool -> newtype
| secondconstr : (bool * bool) -> newtype.
Check (3 : bool).
Check (firstconstr 3).
Fail Check (secondconstr (3, true)).
Check (secondconstr (#pair bool bool 3 true)).
The failure message is The term "(3, true)" has type "(nat * bool)%type" while it is expected to have type "(bool * bool)%type". Obviously the type system can figure out the type that it is supposed to be, but can't decide to coerce the value properly.
Is there a way to declare the coercion in such a way that tuples (and other polymorphic data types with inferred types) are coerced properly?

Maybe you can make a notation that desugars to an annotation so the coercion goes through, assuming the pair is always constructed explicitly (that seems fair for a typing judgement G |- x : T where x : T is a pair, although I think the whole judgement is more commonly seen as a triple).
Here's a PoC with the minimal example:
Notation "'secondconstr'' ( x , y )" := (secondconstr (x : bool, y)).
Check (secondconstr' (3, true)).
And in the context of your types judgement, it might look like this:
Notation "Gamma |- v : T" := (types Gamma (v : value, T))
(at level 100).

Related

What are the rules of Coq implicit types deduction in Inductive definitions?

Consider this type that has X as an implicit type.
Inductive list' {X:Type} : Type :=
| nil'
| cons' (x : X) (l : list').
Coq deduced that type of the second argument of cons' is #list' A:
Fail Check cons' a (cons' b nil'). (* "cons' b nil'" expected to have type "#list' A"*)
But how was this type deduced unambiguously?
We can create another type:
Inductive list'' {X:Type} : Type :=
| nil''
| cons'' (x : X) (l : #list'' B).
Check cons'' a (cons'' b nil'').
It shows that l could also be #list' B.
To be precise, Coq inferred the type of cons' to be forall {X}, X -> #list' X -> #list' X. Then when you write cons a, Coq works out that you must be building a #list' A, and fills in X with A, thus constraining the second argument to be again of type #list' A.
However, the choice of X over some other type is not the only possible choice, as you noticed. In your second example, cons'' gets type forall {X}, X -> #list'' B -> #list'' X. However, when it is left unspecified, most people most of the time intend their parameters (things on the left side of the colon) to be uniform, that is, the same in the arguments as in the conclusion, which heuristic leads to the choice of X here. In general, Coq doesn't worry too much about making sure it's solutions are unique for things the user left unspecified.
In recent enough versions of Coq, you can use the option Uniform Inductive Parameters to specify that all parameters are uniform, or use a | to separate the uniform from the non-uniform parameters. In the case of lists, that would look like
Inductive list' (X:Type) | : Type :=
| nil'
| cons' (x : X) (l : list').
Note that with the |, in the declaration of constructors list' has type Type, while without the |, list' has type Type -> Type, and there is a constraint that the conclusion of the constructor has to be list X (while the arguments can use list other_type freely).

Coq constructor can't take two arguments of different types?

I am just getting started with Coq and am confused as to why this isn't allowed.
Inductive prod: Type :=
| pair (n1: nat n2: bool).
I get a "The reference n2 was not found in the current
environment" complaint.
When I make both arguments nats, or both arguments bools, like this
Inductive prod: Type :=
| pair (n1 n2: bool).
it doesn't complain.
In between one set of parentheses you can only have arguments of one type.
Inductive prod : Type :=
| pair (x y : bool).
But you cannot indeed have several types, the syntax for it is to use several sets of brackets:
Inductive prod : Type :=
| pair (x : nat) (y : bool).

Defining subtype relation in Coq

Is there a way to define subtype relationship in Coq?
I read about subset typing, in which a predicate is used to determine what goes into the subtype, but this is not what I am aiming for. I just want to define a theory in which there is a type (U) and another type (I), which is subtype of (U).
There is no true subtyping in Coq (except for universe subtyping, which is probably not what you want). The closest alternative is to use coercions, which are functions that the Coq type checker inserts automatically whenever it is expecting an element of one type but finds an element of another type instead. For instance, consider the following coercion from booleans to natural numbers:
Definition nat_of_bool (b : bool) : nat :=
if b then 1 else 0.
Coercion nat_of_bool : bool >-> nat.
After running this snippet, Coq uses nat_of_bool to convert bool to nat, as shown here:
Check true + 3.
(* true + 3 : nat *)
Thus, bool starts behaving almost as if it were a subtype of nat.
Though nat_of_bool does not appear here, it is just being hidden by Coq's printer. This term is actually the same thing as nat_of_bool true + 3, as we can see by asking Coq to print all coercions:
Set Printing Coercions.
Check true + 3.
(* nat_of_bool true + 3 : nat *)
The :> symbol you had asked about earlier, when used in a record declaration, is doing the same thing. For instance, the code
Record foo := Foo {
sort :> Type
}.
is equivalent to
Record foo := Foo {
sort : Type
}.
Coercion sort : foo >-> Sortclass.
where Sortclass is a special coercion target for Type, Prop and Set.
The Coq user manual describes coercions in more detail.

Coq: Bypassing the uniform inheritance condition

I've trouble understanding the (point of the) gauntlet one has to pass to bypass the uniform inheritance condition (UIC). Per the instruction
Let /.../ f: forall (x₁:T₁)..(xₖ:Tₖ)(y:C u₁..uₙ), D v₁..vₘ be a
function which does not verify the uniform inheritance condition. To
declare f as coercion, one has first to declare a subclass C' of C
/.../
In the code below, f is such a function:
Parameter C: nat -> Type.
Parameter D: nat -> Prop.
Parameter f: forall {x y}(z:C x), D y.
Parameter f':> forall {x y}(z:C x), D y. (*violates uic*)
Print Coercions. (* #f' *)
Yet I do not have to do anything except putting :> to declare it as a coercion. Maybe the gauntlet will somehow help to avoid breaking UIC? Not so:
Definition C' := fun x => C x.
Fail Definition Id_C_f := fun x d (y: C' x) => (y: C d). (*attempt to define Id_C_f as in the manual*)
Identity Coercion Id_C_f: C' >-> C.
Fail Coercion f: C' >-> D. (*Cannot recognize C' as a source class of f*)
Coercion f'' {x y}(z:C' x): D y := f z. (*violates uic*)
Print Coercions. (* #f' #f'' Id_C_f *)
The question: What am I missing here?
I've trouble understanding the (point of the) gauntlet one has to pass to bypass the uniform inheritance condition (UIC).
Intuitively, the uniform inheritance condition says (roughly) "it's syntactically possible to determine every argument to the coercion function just from the type of the source argument".
The developer that added coercions found it easier (I presume) to write the code implementing coercions if the uniform inheritance condition is assumed. I'm sure that a pull request relaxing this constraint and correctly implementing more general coercions would be welcomed!
That said, note that there is a warning message (not an error message) when you declare a coercion that violates the UIC. It will still add it to the table of coercions. Depending on your version of Coq, the coercion might never trigger, or you might get an error message at type inference time when the code applying the coercion builds an ill-typed term because it tries to apply the coercion assuming the UIC holds when it actually doesn't, or (in older versions of Coq) you can get anomalies (see, e.g., bug reports #4114, #4507, #4635, #3373, and #2828).
That said, here is an example where Identity Coercions are useful:
Require Import Coq.PArith.PArith. (* positive *)
Require Import Coq.FSets.FMapPositive.
Definition lookup {A} (map : PositiveMap.t A) (idx : positive) : option A
:= PositiveMap.find idx map.
(* allows us to apply maps as if they were functions *)
Coercion lookup : PositiveMap.t >-> Funclass.
Definition nat_tree := PositiveMap.t nat.
Axiom mymap1 : PositiveMap.t nat.
Axiom mymap2 : nat_tree.
Local Open Scope positive_scope. (* let 1 mean 1:positive *)
Check mymap1 1. (* mymap1 1 : option nat *)
Fail Check mymap2 1.
(* The command has indeed failed with message:
Illegal application (Non-functional construction):
The expression "mymap2" of type "nat_tree"
cannot be applied to the term
"1" : "positive" *)
Identity Coercion Id_nat_tree : nat_tree >-> PositiveMap.t.
Check mymap2 1. (* mymap2 1 : option nat *)
Basically, in the extremely limited case where you have an identifier which would be recognized as the source of an existing coercion if you unfolded its type a bit, you can use Identity Coercion to do that. (You can also do it by defining a copy of your existing coercion with a different type signature, and declaring that a coercion too. But then if you have some lemmas that mention one coercion, and some lemmas that mention the other, rewrite will have issues.)
There is one other use case for Identity Coercions, which is that, when your source is not an inductive type, you can use them for folding and not just unfolding identifiers, by playing tricks with Modules and Module Types; see this comment on #3115 for an example.
In general, though, there isn't a way that I know of to bypass the uniform inheritance condition.

(How) can I define partial coercions in Coq?

I want to set Coq up, without redefining the : with a notation (and without a plugin, and without replacing the standard library or redefining the constants I'm using---no cheating like that), so that I have something like a partial coercion from option nat to nat, which is defined only on Some _. In particular, I want
Eval compute in Some 0 : nat.
to evaluate to 0, and I want
Check None : nat.
to raise an error.
The closest I've managed is the ability to do this with two :s:
Definition dummy {A} (x : option A) := A.
Definition inverted_option {A} (x : option A)
:= match x with Some _ => A | _ => True end.
Definition invert_Some {A} (x : option A) : inverted_option x
:= match x with Some v => v | None => I end.
Coercion invert_Some : option >-> inverted_option.
Notation nat' := (inverted_option (A:=nat) (Some _)).
Eval compute in (Some 0 : nat') : nat.
Check (None : nat') : nat.
(* The term "None" has type "option ?A" while it is expected to have type
"nat'". *)
However, this only works when nat' is a notation, and I can't define a coercion out of a notation. (And trying to define a coercion from inverted_option (Some _) to nat violated the uniform inheritance condition.) I thought I might be able to get around this issue by using canonical structures, but I haven't managed to figure out how to interleave canonical structure resolution with coercion insertion (see also Can canonical structure resolution be interleaved with coercion insertion?).
(I ran into this issue when attempting to answer Coq: Defining a subtype.)