What is a concrete example of the type `Set` and what is the meaning of `Set`? - coq

I've been trying to understand what Set is after encountering it in Adam Chlipala's book in addition to this great discussion in SO. His first example definition binary ops using Set:
Inductive binop : Set := Plus | Times.
in that book he says:
Second, there is the : Set fragment, which declares that we are defining a datatype that should be thought of as a constituent of programs.
Which confuses me. What does Adam mean here?
In addition, I thought that some additional concrete examples would help my understanding. I am not an expert of Coq so I am not sure what type of examples would help but something simple and very concrete/grounded might be useful.
Note, I have seen that Set is the first "type set" in a the type hierarchy e.g. Set = Type(0) <= Type = Type(1) <= Type(2) <= ... . I guess this sort of makes sense intuitively like I'd assume nat \in Type and all usual programming types to be in it but not sure what would be in Type that wouldn't be in Set. Perhaps recursive types? Not sure if that is the right example but I am trying to wrap my head around what this concept means and it's conceptual (& practical) usefulness.

Though Set and Type are different in Coq, this is mostly due to historical reasons. Nowadays, most developments do not rely on Set being different from Type. In particular, Adam's comment would also make sense if you replace Set by Type everywhere. The main point is that, when you want to define a datatype that you can compute with during execution (e.g. a number), you want to put it in Set or Type rather than Prop. This is because things that live in Prop are erased when you extract programs from Coq, so something defined in Prop would end up not computing anything.
As for your second question: Set is something that lives in Type, but not in Set, as the following snippet shows.
Check Set : Type. (* This works *)
Fail Check Set : Set.
(* The command has indeed failed with message: *)
(* The term "Set" has type "Type" while it is expected to have type *)
(* "Set" (universe inconsistency: Cannot enforce Set+1 <= Set). *)
This restriction is in place to prevent paradoxes in the theory. This is pretty much the only difference you see between Set and Type by default. You can also make them more different by invoking Coq with the -impredicative-set option:
(* Needs -impredicative-set; otherwise, the first line will also fail.*)
Check (forall A : Set, A -> A) : Set.
Universe u.
Fail Check (forall A : Type#{u}, A -> A) : Type#{u}.
(* The command has indeed failed with message: *)
(* The term "forall A : Type, A -> A" has type "Type#{u+1}" *)
(* while it is expected to have type "Type#{u}" (universe inconsistency: Cannot enforce *)
(* u < u because u = u). *)
Note that I had to add the Universe u. declaration to force the two occurrences of Type to be at the same level. Without this declaration, Coq would silently put the two Types at different universe levels, and the command would be accepted. (This would not mean that Type would have the same behavior as Set in this example, since Type#{u} and Type#{v} are different things when u and v are different!)
If you're wondering why this feature is useful, it is not by chance. The overwhelming majority of Coq developments does not rely on it. It is turned off by default because it is incompatible with a few axioms that are generally considered more useful in Coq developments, such as the strong law of the excluded middle:
forall A : Prop, {A} + {~ A}
With -impredicative-set turned on, this axiom yields a paradox, while it is safe to use by default.

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

How to prove that "Type <> Set" (i.e. Type is not equal to Set) in Coq?

Is there an equality or inequality relation between Type and Set in Coq ?
I am learning about Coq's type system and understand that the type of Set is Type#{Set+1}, and that the type of Type#{k} is Type#{k+1}. I tried to prove that Type = Set, and then tried to prove Type <> Set, but I failed in both cases.
I started with
Lemma set_is_type : Type = Set.
Proof.
reflexivity.
which gives an error message saying that Unable to unify "Set" with "Type#{Top.74}".
Then I tried
Lemma set_is_not_type : Type <> Set.
Proof.
intros contra.
At this point I do not know how to proceed. The tactic discriminate did not work, neither inversion contra.
Which one of the above two lemmas can be proved?
This actually isn't an entirely trivial theorem. To show that Type = Set results in a paradox (and hence that having separate levels of Type is necessary), you'll need to use a standard result akin to Russell's paradox from set theory. Specifically, you'll need Hurken's paradox, which essentially says that smaller Types can't be on equal footing to larger Types (remember that Type is polymorphic in Coq, and in particular, Set is the lowest level (or second lowest if you include Prop)).
The particular theorem we want can be found in the standard library.
Require Logic.Hurkens.
Import Logic.Hurkens.TypeNeqSmallType.
Check paradox.
paradox has the type signature forall A : Type, Type = A -> False. This is pretty much what we want to prove, since Set: Type (at least if Type is large enough).
Lemma set_is_not_type: Type <> Set.
Proof.
intro F.
exact (paradox _ F).
Defined.
Coq automatically sets restrictions on the Type in this lemma to ensure that Set: Type.
On the other hand, Set is equal to some level of Type, so we should be able to prove that Type = Set with some different constraints on this Type. The easiest way I found to do this was to prove that Type = Type, but then instantiate this theorem with Set. For whatever reason, as you found, reflexivity can't enforce universe constraints by itself. To do this, we need to make both the lemmas universe polymorphic so that they can be instantiated with a particular universe level.
Polymorphic Lemma type_is_type: Type = Type.
Proof.
reflexivity.
Defined.
Polymorphic Lemma type_is_set: Type = Set.
Proof.
apply type_is_type.
Defined.
The easier way to make everything universe polymorphic is to put Set Universe Polymorphism. before everything.

Why does Coq use unnamed parameters in Inductive Types of Propositions?

I was looking at IndProp and I saw:
Fail Inductive wrong_ev (n : nat) : Prop :=
| wrong_ev_0 : wrong_ev 0
| wrong_ev_SS : ∀ n, wrong_ev n → wrong_ev (S (S n)).
(* ===> Error: A parameter of an inductive type n is not
allowed to be used as a bound variable in the type
of its constructor. *)
except that it seems to behave exactly as if it was taking an argument but it seems to throw an error. Why is this?
The text provides some explanation but I don't understand it:
what I don't understand specifically it. The part I don't understand is the part it says:
it is allowed to take different values in the types
why is it saying "in the types"? Types are NOT the input, values are. Why is it saying this? It seems extremely confusing. I know (extremely vaguely) that there is such a thing as "dependent types" but is that what it's referring too? Shouldn't it be arguments? Don't constructors take value or "stuff" and return an object of some type?
Why does it seem that the signature of the Inductive type (which really I just view it as a function that builds things are returns objects of some type) missing the arguments?
More context from text where explanation seems to appear:
This definition is different in one crucial respect from previous uses of Inductive: its result is not a Type, but rather a function from nat to Prop — that is, a property of numbers. Note that we've already seen other inductive definitions that result in functions, such as list, whose type is Type → Type. What is new here is that, because the nat argument of ev appears unnamed, to the right of the colon, it is allowed to take different values in the types of different constructors: 0 in the type of ev_0 and S (S n) in the type of ev_SS.
In contrast, the definition of list names the X parameter globally, to the left of the colon, forcing the result of nil and cons to be the same (list X). Had we tried to bring nat to the left in defining ev, we would have seen an error ... We can think of the definition of ev as defining a Coq property ev : nat → Prop, together with primitive theorems ev_0 : ev 0 and ev_SS : ∀n, ev n → ev (S (S n)).
Such "constructor theorems" have the same status as proven theorems.
why is it saying "in the types"? Types are NOT the input, values are
You need to read the whole expression: "in the types of different constructors".
And, indeed, the natural number is different in the return type of the two constructors:
It is 0 for ev_0
And it is S (S n) for ev_SS

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.

What exactly is a Set in Coq

I'm still puzzled what the sort Set means in Coq. When do I use Set and when do I use Type?
In Hott a Set is defined as a type, where identity proofs are unique.
But I think in Coq it has a different interpretation.
Set means rather different things in Coq and HoTT.
In Coq, every object has a type, including types themselves. Types of types are usually referred to as sorts, kinds or universes. In Coq, the (computationally relevant) universes are Set, and Type_i, where i ranges over natural numbers (0, 1, 2, 3, ...). We have the following inclusions:
Set <= Type_0 <= Type_1 <= Type_2 <= ...
These universes are typed as follows:
Set : Type_i for any i
Type_i : Type_j for any i < j
Like in Hott, this stratification is needed to ensure logical consistency. As Antal pointed out, Set behaves mostly like the smallest Type, with one exception: it can be made impredicative when you invoke coqtop with the -impredicative-set option. Concretely, this means that forall X : Set, A is of type Set whenever A is. In contrast, forall X : Type_i, A is of type Type_(i + 1), even when A has type Type_i.
The reason for this difference is that, due to logical paradoxes, only the lowest level of such a hierarchy can be made impredicative. You may then wonder then why Set is not made impredicative by default. This is because an impredicative Set is inconsistent with a strong form of the axiom of the excluded middle:
forall P : Prop, {P} + {~ P}.
What this axiom allows you to do is to write functions that can decide arbitrary propositions. Note that the {P} + {~ P} type lives in Set, and not Prop. The usual form of the excluded middle, forall P : Prop, P \/ ~ P, cannot be used in the same way, because things that live in Prop cannot be used in a computationally relevant way.
In addition to Arthur's answer:
From the fact that Set is located at the bottom of the hierarchy,
it follows that Set is the type of the “small” datatypes and function types, i.e. the ones whose values do not directly or indirectly involve types.
That means the following will fail:
Fail Inductive Ts : Set :=
| constrS : Set -> Ts.
with this error message:
Large non-propositional inductive types must be in Type.
As the message suggests, we can amend it by using Type:
Inductive Tt : Type :=
| constrT : Set -> Tt.
Reference:
The Essence of Coq as a Formal System by B. Jacobs (2013), pdf.