refining types with modules and typeclasses - coq

I'm not very familiar with modules or typeclasses in Coq, but based on my basic understanding of them, I believe I have a problem where I should use them.
I want to define a sum function that adds all the elements of a polymorphic list t. It should only work when the type of elements of the list (t) has some definition for plus_function and plus_id_element. The definition of sum I'd like to write would be something like this:
Fixpoint sum {t : Type} (l : list t) :=
match l with
| Nil => plus_id_element t
| Cons x xs => ((plus_function t) x (sum xs))
end.
I don't know what's the usual way to achieve something like this in Coq. I believe in Idris, for example, one would replace t by an interface/typeclass that defines plus_function and plus_id_element. Although typeclasses exist in Coq, I haven't seen them used very often and I believe people usually use modules instead to achieve something similar. I'm not sure if I'm mixing unrelated concepts. Are modules and typeclasses useful for this problem? What would be the recommended approach?

Indeed typeclasses were designed for this exact task, but then you face the hard problem of designing the particular class hierarchy that will fit your problem well.
Coq doesn't provide a standard hierarchy of mathematical operators, and there are many delicate trade-offs in building one with regard to the choice of classes, operators, and axioms.
I thus recommend starting from a mature development such as the MathComp library. MathComp is based on "Canonical Structures" which are a similar notion to type classes, and provides quite a few ready to use classes. The Packaging Mathematical Structures" paper contains more details, but the basic idea is that types pack their operators. For example, if you want to reason about abelian modules you can use the zmodType structure:
From mathcomp Require Import all_ssreflect all_algebra.
Open Scope ring_scope.
Definition sum (A: zmodType) (s : seq A) := foldr +%R 0 s.
to define the sum over a list of elements of the abelian group A. Even better, don't define you own sum operator and just use the one provided by the library: \sum_(x <- s) x:
Lemma eq_sum (A: zmodType) (s : seq A) : sum s = \sum_(x <- s) x.
Proof. by rewrite unlock. Qed.

Related

Type inequality without cardinality arguments

How can I get Coq to let me prove syntactic type inequality?
Negating univalence
I've read the answer to this question, which suggests that if you assume univalence, then the only way to prove type inequality is through cardinality arguments.
My understanding is - if Coq's logic is consistent with univalence, it should also be consistent with the negation of univalence. While I get that the negation of univalence would really be that some isomorphic types are non-equal, I believe it should be possible to express that no isomorphic types (that aren't identical) are equal.
Inequality for type constructors
In effect, I would like Coq to treat types and type constructors as inductive definitions, and do a typical inversion-style argument to say that my two very clearly different types are not equal.
Can it be done? This would need to be:
Useable for concrete types i.e. no type variables, and so
Not necessarily decidable
That strikes me as being weak enough to be consistent.
Context
I have a polymorphic judgement (effectively an inductive type with parameters forall X : Type, x -> Prop) for which the choice of X is decided by the constructors of the judgement.
I want to prove that, for all judgements for a certain choice of X (say X = nat) some property holds, but if I try to use inversion, some constructors give me hypotheses like nat = string (for example). These type equality hypotheses appear even for types with the same cardinality, so I can't (and don't want to) make cardinality arguments to produce a contradiction.
The unthinkable...
Should I produce an Inductive closed-world encoding of the types I care about, and let that be the polymorphic variable of the above judgement?
If you want to use type inequality, I think that the best you can do is to assume axioms for every pair of types you care about:
Axiom nat_not_string : nat <> string.
Axiom nat_not_pair : forall A B, nat <> A * B.
(* ... *)
In Coq, there is no first-class way of talking about the name of an inductively defined type, so there shouldn't be a way of stating this family of axioms with a single assumption. Naturally, you might be able to write a Coq plugin in OCaml to generate those axioms automatically every time an inductive type is defined. But the number of axioms you need grows quadratically in the number of types, so I think would quickly get out of hand.
Your "unthinkable" approach is probably the most convenient in this case, actually.
(Nit: "if Coq's logic is consistent with univalence, it should also be consistent with the negation of univalence". Yes, but only because Coq cannot prove univalence.)

define a "dependently typed" module functor

How can I make a dependently typed functor (for lack of a better term) ? I want to do something like the following:
Module Type Element.
...
End Element.
Module Wrapper (E : Element).
...
End Wrapper.
Module DepentlyTypedFunctor (E : Element) (W : Wrapper E).
...
End DepentlyTypedFunctor.
The last definition doesn't work, and I guess I'm looking for the correct syntax, if possible at all. My motivation for this kind of definition is to define theorems inside DependentlyTypedFunctor that work for all Wrappers that contain any instance of Element, similar to how one could define a theorem for vectors, forall (E : Element) (W : Wrapper E), some_proposition E W.
I think you just meant to make Wrapper a Module Type. If it's not a module type, there's only one such module and you can just write DependentlyTypedFunctor over E. This might not be sufficient if you have opaque implementations of Element, though, in which case different instantiations of Wrapper might not be equal to each other.
If this is a problem, you might just want to use records instead of modules.

General Advice about When to Use Prop and When to use bool

I am formalizing a grammar which is essentially one over boolean expressions. In coq, you can get boolean-like things in Prop or more explicitly in bool.
So for example, I could write:
true && true
Or
True /\ True
The problem is that in proofs (which is what I really care about) I can do a case analysis in domain bool, but in Prop this is not possible (since all members are not enumerable, I suppose). Giving up this tactic and similar rewriting tactics seems like a huge drawback even for very simple proofs.
In general, what situations would one choose Prop over bool for formalizing? I realize this is a broad question, but I feel like this is not addressed in the Coq manual sufficiently. I am interested in real world experience people have had going down both routes.
There are lots of different opinions on this. My personal take is that you are often better off not making this choice: it makes sense to have two versions of a property, one in Prop, the other one in bool.
Why would you want this? As you pointed out, booleans support case analysis in proofs and functions, which general propositions do not. However, Prop is more convenient to use in certain cases. Suppose you have a type T with finitely many values. We can write a procedure
all : (T -> bool) -> bool
that decides whether a boolean property P : T -> bool holds of all elements of T. Imagine that we know that all P = true, for some property P. We might want to use this fact to conclude that P x = true for some value x. To do this, we need to prove a lemma about all:
allP : forall P : T -> bool,
all P = true <-> (forall x : T, P x = true)
This lemma connects two different formulations of the same property: a boolean one and a propositional one. When reasoning about all in a proof, we can invoke allP to convert freely between the two. We can also have different conversion lemmas:
allPn : forall P,
all P = false <-> (exists x, P x = false)
In fact, we are free to choose any Coq proposition whatsoever to relate to a boolean computation (as long, of course, as we can prove that the two are logically equivalent). For instance, if we would like to have a custom induction principle associated with a boolean property, we can look for an equivalent formulation as an inductively defined proposition.
The Mathematical Components library is a good example of development that follows this style. Indeed, because it is so pervasive there, the library provides a special view mechanism for writing conversion lemmas like the one above and applying them. In plain Coq, we can also use the rewrite tactic to apply logical equivalences more conveniently.
Of course, there are many situations where it does not make sense to have two formulations of the same property. Sometimes, you are forced to use Prop, because the property you care about is undecidable. Sometimes, you might feel that you wouldn't gain anything by writing your property in Prop, and may keep it only as a boolean.
In addition to the Software Foundations chapter linked above, this answer discusses the difference between bool and Prop in more depth.

Unfolding a proof term in Coq

I wonder if there is a way to obtain the proof term (serialized via Print or not) at some level beyond the current context (or just down to primitives). For example, executing the following
From mathcomp Require Import odd_order.PFsection14.
Print Feit_Thompson.
results in
Feit_Thompson =
fun (gT : fingroup.FinGroup.type)
(G : fingroup.group_of (gT:=gT)
(ssreflect.Phant
(fingroup.FinGroup.arg_sort
(fingroup.FinGroup.base gT)))) =>
BGsection7.minSimpleOdd_ind no_minSimple_odd_group (gT:=gT)
(G:=G)
: forall (gT : fingroup.FinGroup.type)
(G : fingroup.group_of (gT:=gT)
(ssreflect.Phant
(fingroup.FinGroup.arg_sort
(fingroup.FinGroup.base gT)))),
is_true
(ssrnat.odd
(fintype.CardDef.card
(T:=fingroup.FinGroup.arg_finType
(fingroup.FinGroup.base gT))
(ssrbool.mem
(finset.SetDef.pred_of_set
(fingroup.gval G))))) ->
is_true (nilpotent.solvable (fingroup.gval G))
but i would like to unfold the identifiers (theorems and definitions) used in the proof term such as no_minSimple_odd_group to their proof terms. I suspect that the opacity of theorems and lemmas might pose an obstacle to this purpose.
The naive solution i can think of is to recursively query each identifier via Print. Or a less naive (and less ideal due to the change in the language representing the proof term) solution, via program extraction.
I am not sure if there is a direct way of doing that, but it wouldn't be too hard to implement, at this level opacity is just a flag and can be bypassed.
However, I wonder about what do you want to achieve?
Note that most proof terms obtained that way are going to be just unmanageable, specially unfolding will quickly lead to a worse than exponential size blowup.

Type theory: type kinds

I've read a lot of interesting things about type kinds, higher-kinded types and so on. By default Haskell supports two sorts of kind:
Simple type: *
Type constructor: * → *
Latest GHC's language extensions ConstraintKinds adds a new kind:
Type parameter constraint: Constraint
Also after reading this mailing list it becomes clear that another type of kind may exists, but it is not supported by GHC (but such support is implemented in .NET):
Unboxed type: #
I've learned about polymorphic kinds and I think I understand the idea. Also Haskell supports explicitly-kinded quantification.
So my questions are:
Do any other types of kinds exists?
Are there any other kind-releated language features?
What does subkinding mean? Where is it implemented/useful?
Is there a type system on top of kinds, like kinds are a type system on top of types? (just interested)
Yes, other kinds exist. The page Intermediate Types describes other kinds used in GHC (including both unboxed types and some more complicated kinds as well). The Ωmega language takes higher-kinded types to the maximum logical extension, allowing for user-definable kinds (and sorts, and higher). This page proposes a kind system extension for GHC which would allow for user-definable kinds in Haskell, as well as a good example of why they would be useful.
As a short excerpt, suppose you wanted a list type which had a type-level annotation of the length of the list, like this:
data Zero
data Succ n
data List :: * -> * -> * where
Nil :: List a Zero
Cons :: a -> List a n -> List a (Succ n)
The intention is that the last type argument should only be Zero or Succ n, where n is again only Zero or Succ n. In short, you need to introduce a new kind, called Nat which contains only the two types Zero and Succ n. Then the List datatype could express that the last argument is not a *, but a Nat, like
data List :: * -> Nat -> * where
Nil :: List a Zero
Cons :: a -> List a n -> List a (Succ n)
This would allow the type checker to be much more discriminative in what it accepts, as well as making type-level programming much more expressive.
Just as types are classified with kinds, kinds are classified with sorts.
Ωmega programming language has a kind system with user definable kinds at any level. (So says its wiki. I think it refers to the sorts and the levels above, but I am not sure.)
There has been a proposal to lift types into the kind level and values into the type level. But I don't know if that is already implemented (or if it ever will reach "prime time")
Consider the following code:
data Z
data S a
data Vec (a :: *) (b :: *) where
VNil :: Vec Z a
VCons :: a -> Vec l a -> Vec (S l) a
This is a Vector that has it's dimension encoded in the type. We are using Z and S to generate the natural number. That's kind of nice but we cannot "type check" if we are using the right types when generating a Vec (we could accidently switch length an content type) and we also need to generate a type S and Z, which is inconvenient if we already defined the natural numbers like so:
data Nat = Z | S Nat
With the proposal you could write something like this:
data Nat = Z | S Nat
data Vec (a :: Nat) (b :: *) where
VNil :: Vec Z a
VCons :: a -> Vec l a -> Vec (S l) a
This would lift Nat into the kind level and S and Z into the type level if needed. So Nat is another kind and lives on the same level as *.
Here is the presentation by Brent Yorgey
Typed type-level functional programming in GHC