Coq: Defining a type class instance - class

In the development below, I get a strange error when trying to define an instance of a single-method typeclass:
Universe ARG. Definition ARG := Type#{ARG}.
Universe ARG0. Definition ARG0 := Type#{ARG0}.
Universe ARG1. Definition ARG1 := Type#{ARG1}.
Universe ARG2. Definition ARG2 := Type#{ARG2}.
Constraint ARG<ARG0, ARG0<ARG1, ARG1<ARG2.
Inductive SR: ARG := Phy | Sen | Inf | Lim.
Parameter CA: Prop.
Parameter X: SR -> CA -> ARG -> ARG.
Parameter X': SR -> CA -> ARG -> ARG0.
Parameter XP: SR -> CA -> ARG -> ARG1.
Parameter XP': SR -> CA -> ARG -> ARG2.
Inductive tri:Set := one | two | three.
Definition iX' (t:tri): SR -> CA -> ARG -> ARG2 := match t with one => X' | two => XP | three => XP' end.
Parameter gk:> forall (b:SR)(d:CA)(c:ARG), X' b d c -> iX' one b d c.
Parameter gl:> forall (b:SR)(d:CA)(c:ARG), XP b d c -> iX' two b d c.
Parameter gm:> forall (b:SR)(d:CA)(c:ARG), XP' b d c -> iX' three b d c.
Definition iX'bsko {b:tri}{s:SR}{k:CA}{o:ARG} := iX' b s k o.
Parameter foo: forall {b:tri}{s:SR}{k:CA}{o:ARG}, iX' b s k o.
Fail Check foo: forall {b:tri}{s:SR}{k:CA}{o:ARG}, iX' b s k o. (*Why?*)
Check foo: iX'bsko.
Class CONN := p5 (x y z:ARG): x -> y -> z.
Instance cco: CONN := fun x y iX'bsko (_:x) (_:y) => foo.
(* Error: "foo" has type "iX' ?b#{y0:=x0; y1:=y0} ?s#{y0:=x0; y1:=y0} ?k#{y0:=x0; y1:=y0} ?o#{y0:=x0; y1:=y0}"
while it is expected to have type "iX'bsko". *)
The cause of the error seems to be that foo doesn't have type iX'bsko, while 2 lines above foo: iX'bsko type checked. How do I solve this problem?

To answer your comment (*Why?*), the issue is that foo means #foo _ _ _ _. The following succeds:
Check #foo: forall {b:tri}{s:SR}{k:CA}{o:ARG}, iX' b s k o.
To answer your question, you have shot yourself in the foot by shadowing the global iX'bsko with a local opaque variable.
If you change
Instance cco: CONN := fun x y iX'bsko (_:x) (_:y) => foo.
to
Instance cco: CONN := fun x y not_really_iX'bsko' (_:x) (_:y) => foo.
you get
Error:
In environment
x : ARG
y : ARG
not_really_iX'bsko : ARG
x0 : x
y0 : y
The term "foo" has type
"iX' ?b#{y0:=x0; y1:=y0} ?s#{y0:=x0; y1:=y0} ?k#{y0:=x0; y1:=y0}
?o#{y0:=x0; y1:=y0}" while it is expected to have type
"not_really_iX'bsko".
This is not surprising. CONN is the type forall x y z : Type#{ARG}, x -> y -> z. This type has no inhabitants:
Lemma no_conn : CONN -> False.
Proof. exact (fun cco => cco True True False I I). Qed.
Perhaps you meant to make x, y, and z arguments to CONN instead, writing something like this?
Class CONN (x y z:ARG) := p5 : x -> y -> z.
Instance cco x y : CONN x y iX'bsko := fun (_:x) (_:y) => foo.
Note that this fails with a much more clear-cut error message:
The term "iX'bsko" has type "ARG2" while it is expected to have type
"ARG" (universe inconsistency).
If you instead do
Class CONN (x y z:ARG2) := p5 : x -> y -> z.
Instance cco x y : CONN x y iX'bsko := fun (_:x) (_:y) => foo.
then you get
Error: Cannot infer the implicit parameter b of iX'bsko whose type is
"tri" in environment:
x, y : ARG2

Related

Error when referencing type variable from another file

I am working upon formalization of groups theory in coq. I have 2 files:
groups.v - contains definitions and theorems for groups
groups_Z.v - contains theorems and definitions for Z group.
groups.v:
Require Import Coq.Setoids.Setoid.
Require Import Coq.Lists.List.
Require Import PeanoNat.
Class Semigroup G : Type :=
{
mult : G -> G -> G;
assoc : forall x y z:G,
mult x (mult y z) = mult (mult x y) z
}.
Class Monoid G `{Hsemi: Semigroup G} : Type :=
{
e : G;
left_id : forall x:G, mult e x = x;
}.
Class Group G `{Hmono: Monoid G} : Type :=
{
inv : G -> G;
left_inv : forall x:G, mult (inv x) x = e;
}.
Declare Scope group_scope.
Infix "*" := mult (at level 40, left associativity) : group_scope.
Open Scope group_scope.
Section Group_theorems.
Parameter G: Type.
Context `{Hgr: Group G}.
(* More theorems follow *)
Fixpoint pow (a: G) (n: nat) {struct n} : G :=
match n with
| 0 => e
| S n' => a * (pow a n')
end.
Notation "a ** b" := (pow a b) (at level 35, right associativity).
End Group_theorems.
Close Scope group_scope.
groups_Z.v:
Add LoadPath ".".
Require Import groups.
Require Import ZArith.
Open Scope group_scope.
Section Z_Groups.
Parameter G: Type.
Context `{Hgr: Group G}.
Definition pow_z (a: groups.G) (z: Z) : G :=
match z with
| Z0 => e
| Zpos x => pow a (Pos.to_nat x)
| Zneg x => inv (pow a (Pos.to_nat x))
end.
Notation "a ** b" := (pow_z a b) (at level 35, right associativity).
End Z_groups.
Close Scope group_scope.
The attempt to define pow_z fails with message:
The term "pow a (Pos.to_nat x)" has type "groups.G" while it is
expected to have type "G".
If we use the different signature: Definition pow_z (a: G) (z: Z) : G
instead of Definition pow_z (a: groups.G) (z: Z) : G.
then it gives another error:
The term "a" has type "G" while it is expected to have type
"groups.G".
How to fix this?
In Coq, the command Parameter G : Type declares a global constant, which is akin to axiomatizing the existence of an abstract Type G : Type. From a theoretical point of view, this should be ok as this axiom is trivially realizable, but I think you meant Variable G : Type to denote a local variable instead.
The errors messages of Coq follow from there because you declare two global constants named G, one in each module. As soon as the second one is declared, the first one is designated by groups.G by Coq (it's the shortest name that disambiguates this constant from others). Now pow operates on and returns a groups.G, while you require pow_z returns a G (which in file groups_Z.v at this location means groups_Z.G, and is different from groups.G).
NB: Group theory has been developed several times in Coq, and if you want to do anything else than experimenting with the system, I would advise you work on top of existing libraries. For example the mathematical components library has a finite group library.
I changed Parameter G: Type. to Variable G: Type in both files and pow_z definition to this:
Definition pow_z (a: G) (z: Z) : G :=
match z with
| Z0 => e
| Zpos x => pow G a (Pos.to_nat x)
| Zneg x => inv (pow G a (Pos.to_nat x))
end.

Coq: Resolve an expression to multiple instances

In a scenario like this, I want a single expression to resolve to multiple instances:
Inductive SR: Prop := Sen | Inf.
Parameter CA S: Prop.
Parameter X: SR -> CA -> Prop -> Prop.
Parameter X': SR -> CA -> Prop -> Set.
Parameter XP: SR -> CA -> Prop -> Type.
Definition iX' (t:bool): SR -> CA -> Prop -> Type := if t then X' else XP.
Context `{b:bool}`{c:bool}`{d:bool}`{s:SR}`{t:SR}`{u:SR}`{k:CA}`{l:CA}`{m:CA}`{o:Prop}`{p:Prop}`{q:Prop}.
Parameter foo: iX' b s k o.
Parameter foo'': iX' d u m q.
Parameter ss: S.
Class CON (f:bool) := an: if f then iX' b s k o -> iX' c t l p -> iX' d u m q else S -> S -> S.
Instance coni: CON true := fun (_:iX' b s k o) (_:iX' c t l p) => foo''.
Instance conj: CON false := fun (_:S) (_:S) => ss.
Check (_: CON false) ss.
Check (_: CON true) foo.
Check (_: CON _) ss.
Check (_: CON _) foo. (*Error: The term "foo" has type "iX' b s k o" while it is expected to have type "S".*)
Is there a way to make the instance resolution work w/ both (_: CON _) foo and (_: CON _) ss? If not, try to succeed in a scenario where the class and/or instances are different, while ... in Check ... ss and Check ... foo is identical, and resolves to functions fun (_:S) (_:S) => ss and fun (_:iX' b s k o) (_:iX' c t l p) => foo'', resp.
Is there any reason to restrict yourself to instances here? If you're already doing this much hackery, you might as well go a bit further and use tactics in terms in notations.
Ltac mkcon arg :=
match constr:(Set) with
| _ => exact ((_ : CON false) arg)
| _ => exact ((_ : CON true) arg)
end.
Notation CON_ arg := ltac:(mkcon arg) (only parsing).
Check (_: CON false) ss.
Check (_: CON true) foo.
Check CON_ ss.
Check CON_ foo.

How can I compare (equality) of two elements of same Set in Coq?

Inductive ty: Set :=
| I
| O.
Definition f (x: ty) (y: ty): nat :=
if x = y then 0 else 1.
I want the function f to compare two terms of type ty but it does not compile and I see this error:
The term x = y has type Prop which is not a (co-)inductive type.
You need to prove that equality is decidable for ty (which can be done automatically using decide equality) and then use that definition in the if ... then ... else ... statement. Concretely:
Inductive ty: Set :=
| I
| O.
Definition ty_eq_dec : forall (x y : ty), { x = y } + { x <> y }.
Proof.
decide equality.
Defined.
Definition f (x: ty) (y: ty): nat :=
if ty_eq_dec x y then 0 else 1.
You can use match to compare the elements of inductive data types.
Definition f x y := match x,y with I, I | O, O => 0 | _,_ => 1 end.
decide equality is a more general tactic and works for infinite sets, but it is good to know that it is match that is doing the real work.

Supplying section arguments for examples

Consider this section:
Section MyMap.
Variables D R : Type.
Fixpoint mymap (f : D -> R) (l : list D) : list R :=
match l with
| nil => nil
| d :: t => f d :: mymap f t
end.
End MyMap.
Here I've used Variables to declare my domain and range types. As a sanity check on the definition of my function, I would like to include an Example:
Example example_map_S : mymap S [0; 1; 2] = [1; 2; 3].
Proof.
simpl; trivial.
Qed.
However it seems I can't do so within my section. Instead I get:
Error: The term "S" has type "nat -> nat" while it is expected to have type "D -> R".
That's not too surprising, so let's try it another way:
Example example_map_S : #mymap nat nat S [0; 1; 2] = [1; 2; 3].
Proof.
simpl; trivial.
Qed.
Which produces:
Error: The term "nat" has type "Set" while it is expected to have type "D -> R".
I suppose that's fair, section-ized Variables aren't the same thing as implicit arguments. But it still leaves the question!
How can I supply concrete Variables to a term before closing the section, in order to create useful Examples?
Section MyMap.
...
If we check the type of mymap inside the section, we get
Check mymap.
(* mymap : (D -> R) -> list D -> list R *)
Of course, we can't unify D and R with nat, since D and R are some locally postulated types.
However, we can sort of simulate your example in this generalized setting, showing the expected property of the mymap function:
Example example_nil (f : D -> R) :
mymap f [] = [] := eq_refl.
Example example_3elems (f : D -> R) (d0 d1 d2 : D) :
mymap f [d0; d1; d2] = [f d0; f d1; f d2] := eq_refl.
End MyMap.

Converting to Fin Type in Coq

Can anyone tell me why the following projection function in COQ doesn't work?
Require Import Vector.
Require Import Fin.
Definition Proj {n:nat}{p:nat}(x:t p+{(exists m : nat, n=p+m)}):=
match x with
inleft y => y
|_ => F1
end.
I get the following error:
Error:
In environment
n : nat
p : nat
x : t p + {(exists m : nat, n = p + m)}
e : exists m : nat, n = p + m
The term "F1" has type "t (S ?6 (* [n, p, x, e, e] *))"
while it is expected to have type "t p".
On the other hand, using concrete values for p works fine:
Require Import Vector.
Require Import Fin.
Definition Proj {n:nat}(x:t 3 + {(exists m : nat, n=3+m)}):=
match x with
inleft y => y
|_ => F1
end.
Eval compute in (Proj (of_nat 2 3)) = FS (FS F1): t 3.
I'm assuming that you want Proj to return a value of type t p. That is impossible for p = 0 (because t 0 is the empty set), and that's why you cannot implement Proj for arbitrary p. If you extend you function to take a proof that p is not equal to 0, then you can implement it as follows. Read Adam's CPDT Chapter on Dependent Types to understand what is going on here.
Definition Proj {n:nat} {p:nat} (x:t p+{(exists m : nat, n=p+m)}) : p <> 0 -> t p :=
match x with
| inleft y => fun _ => y
| _ => match p with
| 0 => fun h => False_rect _ (h eq_refl)
| S _ => fun _ => F1
end
end.