Suppose we have a type A with an equivalence relation (===) : A -> A -> Prop on it.
On top of that there is a function f : A -> option A.
It so happens that this function f is "almost" Proper with respect to equiv. By "almost" I mean the following:
Lemma almost_proper :
forall a1 a2 b1 b2 : A,
a1 === a2 ->
f a1 = Some b1 -> f a2 = Some b2 ->
b1 === b2.
In other words, if f succeeds on both inputs, the relation is preserved, but f might still fail on one and succeed on the other. I would like to express this concept concisely but came up with a few questions when trying to do so.
I see three solutions to the problem:
Leave everything as is. Do not use typeclasses, prove lemmas like the one above. This doesn't look good, because of the proliferation of preconditions like x = Some y, which create complications when proving lemmas.
It is possible to prove Proper ((===) ==> equiv_if_Some) f when equiv_if_Some is defined as follows:
Inductive equiv_if_Some {A : Type} {EqA : relation A} `{Equivalence A EqA} : relation (option A) :=
| equiv_Some_Some : forall a1 a2, a1 === a2 -> equiv_if_Some (Some a1) (Some a2)
| equiv_Some_None : forall a, equiv_if_Some (Some a) None
| equiv_None_Some : forall a, equiv_if_Some None (Some a)
| equiv_None_None : equiv_if_Some None None.
One problem here is that this is no longer an equivalence relation (it is not transitive).
It might be possible to prove Almost_Proper ((===) ==> (===)) f if some reasonable Almost_Proper class is used. I am not sure how that would work.
What would be the best way to express this concept? I am leaning toward the second one, but perhaps there are more options?
For variants 2 and 3, are there preexisting common names (and therefore possibly premade definitions) for the relations I describe? (equiv_if_Some and Almost_Proper)
2 if it simplifies your proofs.
The fact that it's not an equivalence relation is not a deal breaker, but it does limit the contexts in which it can be used.
equiv_if_Some might be nicer to define as an implication (similar to how it appears in the almost_proper lemma) than as an inductive type.
You may also consider using other relations (as an alternative to, or in combination with equiv_if_Some):
A partial order, that can only relate None to Some but not Some to None
A partial equivalence relation, that can only relate Somes.
Related
I'm self studying Coq and playing with it. I wanted to try and write a function that computes blood type based on two alleles. However, I'm getting an error "Tactic failure: The relation (fun x y : BloodType => x <> y) is not a declared reflexive relation." when trying to prove that any other pair of alleles but TypeO will not result type TypeO blood.
There's three alleles:
Inductive BloodTypeAllele : Type :=
| BloodTypeA
| BloodTypeB
| BloodTypeO.
And four blood types:
Inductive BloodType : Type :=
| TypeA
| TypeB
| TypeAB
| TypeO.
Mapping between them is as follows:
Fixpoint bloodType (a b : BloodTypeAllele) : BloodType :=
match a, b with
| BloodTypeA, BloodTypeA => TypeA
| BloodTypeA, BloodTypeO => TypeA
| BloodTypeA, BloodTypeB => TypeAB
| BloodTypeB, BloodTypeB => TypeB
| BloodTypeB, BloodTypeA => TypeAB
| BloodTypeB, BloodTypeO => TypeB
| BloodTypeO, BloodTypeA => TypeA
| BloodTypeO, BloodTypeB => TypeB
| BloodTypeO, BloodTypeO => TypeO
end.
I can prove that BloodTypeO and BloodTypeO results TypeO blood.
Theorem double_O_results_O_type :
bloodType BloodTypeO BloodTypeO = TypeO.
Proof.
reflexivity.
Qed.
But I can't prove that any other combination will not result to TypeO blood.
Theorem not_double_O_does_not_result_O_type :
forall (b1 b2 : BloodTypeAllele),
b1 <> BloodTypeO \/ b2 <> BloodTypeO ->
bloodType b1 b2 <> TypeO.
Proof.
intros b1 b2 H.
destruct b1.
- destruct b2.
+ simpl. reflexivity.
Because I'm getting following error:
"Tactic failure: The relation (fun x y : BloodType => x <> y) is not a declared reflexive relation. Maybe you need to require the Coq.Classes.RelationClasses library."
I tried importing the library, but the error remained the same. I'm very new to Coq, so I'm probably looking over something very obvious.
One part of the problem is that you don't reason with a negated predicate in the same way as you reason on the direct predicate. You have to think again in terms of logic, before expecting Coq to work for you.
Let's go back to a very basic logical inference "All humans are mortal, Socrates is human, therefore he is mortal". If my cat is mortal, does it mean my cat is human? No! When you work with negation, the problem is very close to this.
Now, let's concentrate on your problem. There is a specific tactic to help prove basic instances of equality reflexivity. There is also a specific tactic to help prove basic instances of "non-equality". This tactic is called discriminate and it will work in your case.
Negation of equality appears in two different fashion in your exercise. Sometimes you need to prove a negated equality that is obvious to your naked eye and in this case, discriminate may do the job. Sometimes, you need to prove a negated equality that is obviously not provable (it will happen later in you exercise, I tried). In that case, the way to progress is to discover that there is an assumption in you goal that actually contains an inherent contradiction, or that two hypotheses are contradictory to each other. In that case, the solution is to try destruct H where H is the hypothesis that is obviously wrong.
In the case of your exercise, you will also need to understand how to cope with an or in an hypothesis, destruct will still be relevant for that case.
I suggest you read the free document (coq in a hurry)[https://cel.archives-ouvertes.fr/inria-00001173v6/document] as a tutorial for this. In particular, it explains that for every logical construct, the way to handle this construct is different, whether the construct appears as the conclusion of a goal or as an hypothesis. There is a short table to be used as a first hint list for most basic reasoning steps.
Another piece of advice: don't use the Fixpoint command when the function you wish to define is not recursive. In you case the function bloodType should have defined using the Definition keyword. Using Fixpoint makes the definition uselessly complicated and this may bite you later in your experiments.
I am excited to see you learn on your own, have fun, and ask questions!
I can define the following inductive type:
Inductive T : Type -> Type :=
| c1 : forall (A : Type), A -> T A
| c2 : T unit.
But then the command Check (c1 (T nat)) fails with the message: The term T nat has type Type#{max(Set, Top.3+1)} while it is expected to have type Type#{Top.3} (universe inconsistency).
How can I tweak the above inductive definition so that c1 (T nat) does not cause a universe inconsistency, and without setting universe polymorphism on?
The following works, but I would prefer a solution without adding equality:
Inductive T (A : Type) : Type :=
| c1 : A -> T A
| c2' : A = unit -> T A.
Definition c2 : T unit := c2' unit eq_refl.
Check (c1 (T nat)).
(*
c1 (T nat)
: T nat -> T (T nat)
*)
Let me first answer the question of why we get the universe inconsistency in the first place.
Universe inconsistencies are the errors that Coq reports to avoid proofs of False via Russell's paradox, which results from considering the set of all sets which do not contain themselves.
There's a variant which is more convenient to formalize in type theory called Hurken's Paradox; see Coq.Logic.Hurkens for more details. There is a specialization of Hurken's paradox which proves that no type can retract to a smaller type. That is, given
U := Type#{u}
A : U
down : U -> A
up : A -> U
up_down : forall (X:U), up (down X) = X
we can prove False.
This is almost exactly the setup of your Inductive type. Annotating your type with universes, you start with
Inductive T : Type#{i} -> Type#{j} :=
| c1 : forall (A : Type#{i}), A -> T A
| c2 : T unit.
Note that we can invert this inductive; we may write
Definition c1' (A : Type#{i}) (v : T A) : A
:= match v with
| c1 A x => x
| c2 => tt
end.
Lemma c1'_c1 (A : Type#{i}) : forall v, c1' A (c1 A v) = v.
Proof. reflexivity. Qed.
Suppose, for a moment, that c1 (T nat) typechecked. Since T nat : Type#{j}, this would require j <= i. If it gave us that j < i, then we would be set. We could write c1 Type#{j}. And this is exactly the setup for the variant of Hurken's that I mentioned above! We could define
u = j
U := Type#{j}
A := T Type#{j}
down : U -> A := c1 Type#{j}
up : A -> U := c1' Type#{j}
up_down := c1'_c1 Type#{j}
and hence prove False.
Coq needs to implement a rule for avoiding this paradox. As described here, the rule is that for each (non-parameter) argument to a constructor of an inductive, if the type of the argument has a sort in universe u, then the universe of the inductive is constrained to be >= u. In this case, this is stricter than Coq needs to be. As mentioned by SkySkimmer here, Coq could recognize arguments which appear directly in locations which are indices of the inductive, and disregard those in the same way that it disregards parameters.
So, to finally answer your question, I believe the following are your only options:
You can Set Universe Polymorphism so that in T (T nat), your two Ts take different universe arguments. (Equivalently, you can write Polymorphic Inductive.)
You can take advantage of how Coq treats parameters of inductive types specially, which mandates using equality in your case. (The requirement of using equality is a general property of going from indexed inductive types to parameterized inductives types---from moving arguments from after the : to before it.)
You can pass Coq the flag -type-in-type to entirely disable universe checking.
You can fix bug #7929, which I reported as part of digging into this question, to make Coq handle arguments of constructors which appear in index-position in the inductive in the same way it handles parameters of inductive types.
(You can find another edge case of the system, and manage to trick Coq into ignoring the universes you want to slip past it, and probably find a proof of False in the process. (Possibly involving module subtyping, see, e.g., this recent bug in modules with universes.))
In the paper
Univalence as a Principle of Logic, Awodey writes on page 7:
Let us consider the example of intensional versus extensional type theory. The extensional theory has an apparently “stronger” notion of equality, because it permits one to simply substitute equals for equals in all contexts. In the intensional system, by contrast, one can have a = b and a statement Φ(a) and yet not have Φ(b).
I do not understand this, because I thought this is the basic property of equality.
Also, in Coq one can simply prove:
Theorem subs: forall (T:Type)(a b:T)(p:a=b)(P:T-> Prop), P a -> P b.
intros.
rewrite <- p.
assumption.
Qed.
If I am not mistaken, in Awodey's paper, the notation Φ(a) means substituting some implicit free variable in Φ for the expression a.
In my answer, I will use the following more explicit notation instead (which corresponds to Φ(a) in the paper):
Φ[z ⟼ a]
This means that in the expression Φ, free variable z will be substituted for expression a.
Example:
(x = z)[z ⟼ a]
results in
(x = a)
Now, I will assume that you are already familiar with the usual presentation of Type Theory by means of inference rules, as in Appendix A.2 in the HoTT Book.
Type Theory uses two notions of equality.
Identity Types: Usually written using the symbol = in inference rules. In order to conclude an statement like a = b, we need to provide a proof term for it. For example, let's have a look at the introduction rule for identity types:
a : A
---------------- (=)-INTRO
refl a : a = a
Here, refl a is acting as the proof term or evidence that justifies our claim that a = a holds (namely, refl a is representing the trivial or reflexivity proof). So, an statement like p : a = b is expressing that a and b can be identified due to evidence p.
Definitional Equality: Usually written using the symbol ≡ in inference rules. The statement a ≡ b means that a and b are interchangeable, replaceable anywhere, or substitutionally equivalent. This equality captures notions like "by definition", "by computation", "by simplification". This kind of equality does not carry a proof term with it, i.e. it is not a typing statement. This is the kind of equality Coq uses implicitly when you use the tactics simpl and compute. For example, let's have a look at the reflexivity rule for ≡:
a : A
--------- (≡)-REFLE
a ≡ a
Notice that there is no proof term to the left of a ≡ a (compare with the (=)-INTRO rule above). In this case, the proof system is treating a ≡ a as a fact, something that holds without the need to state explicitly its justification, since the only use of ≡ in the proof system will be for rewriting expressions.
That ≡ is used only for simplifying expressions, can be found in other inference rules, for example, the type preservation rule for ≡:
a : A A ≡ B
------------------ (≡)-TYPE-PRESERV
a : B
In other words, if you start with a term a of type A, and you know that types A and B are interchangeable, then term a also has type B. Notice that (and this will be important later!!) the proof term or evidence for B did not change, it is still the same proof term as the one used for A.
We can now get into the question.
What differentiates Extensional Type Theory (ETT) from an Intensional Type Theory like HoTT or CoC is the way they treat identity types and definitional equality.
ETT makes identity types and definitional equality interchangeable by adding the following inference rule:
p : a = b
----------- (=)-EXT
a ≡ b
In other words, the evidence p for the identity becomes irrelevant, and we treat a and b as interchangeable in the proof system (thanks to rules like (≡)-TYPE-PRESERV and other similar rules).
Starting from the hypotheses p : a = b and a : A, in ETT we can do stuff like the following:
a : A p : a = b
--------- (≡)-REFLE ----------- (=)-EXT
a ≡ a a ≡ b
------------------------------------- (=)-CONG (*1)
(a = a) ≡ (a = b)
Where (=)-CONG is a congruence rule (i.e. definitionally equivalent terms produce definitionally equivalent identity types), and I am calling this derivation (*1).
Using (*1), we can then derive:
a : A
----------------- (=)-INTRO -------------------- (*1)
refl a : a = a (a = a) ≡ (a = b)
-------------------------------------------------- (≡)-TYPE-PRESERV
refl a : a = b
Where in (*1) we insert the derivation we did above.
In other words, if we ignore the hypotheses a : A and intermediate steps, it is as if we did the following inference:
p : a = b refl a : a = a
-------------------------------------
refl a : a = b
Since ETT is treating a and b as interchangeable (thanks to the hypothesis p : a = b and the (=)-EXT rule), the proof refl a for a = a can be also seen as a proof for a = b. So, it is not hard to see that, in ETT, having a proof for an identity like a = b is sufficient for replacing some or all occurrences of a for b in ANY statement involving a.
Now, what happens in an Intensional Type Theory (ITT)?
In an ITT, the (=)-EXT rule is not assumed. Therefore, we cannot carry out the derivation (*1) we did above, and in particular, the following inference is invalid:
p : a = b refl a : a = a
-------------------------------------
refl a : a = b
This is an example where we have an identity p : a = b, but from the statement (refl a : a = z)[z ⟼ a], we cannot conclude the statement (refl a : a = z)[z ⟼ b]. This is an instance of what Awodey's paper was referring to I think.
Why is this an invalid inference? Because refl a : a = b is forcing a and b to be definitionally equal (i.e. the only way to introduce refl a into a derivation is through the (=)-INTRO rule), but this is not necessarily true from the hypothesis p : a = b. In HoTT, for example, the interval type I (Section 6.3 in the HoTT Book), has two terms 0 : I and 1 : I, they are not definitionally equal, but we have a proof seg : 0 = 1.
The fact that there might exist other identity proofs that are not the trivial or the reflexivity proof, it's what gives an Intentional Type Theory its richness. It is what allows HoTT to have Univalence and Higher Inductive Types, for example.
So, what can we conclude from the hypotheses p : a = b and refl a : a = a in an ITT?
In your question, the theorem you proved in Coq is called the "transport" function in HoTT (Section 2.3 in the HoTT Book). Using your theorem (removing the implicit parameters), you will be able to do the following derivation:
p : a = b refl a : a = a
------------------------------------------
subs p (λx => a = x) (refl a) : a = b
In other words, we can conclude that a = b, but our proof term for this changed! In ETT we simply carried out a substitution (because a and b were interchangeable) allowing us to use the same evidence in the conclusion (namely refl a). But in an ITT, we cannot treat a and b as substitutionally equivalent, due to the richness of the identity types. And to reflect this intention, we need to combine the proofs of the hypotheses to build our new evidence in the conclusion.
So, from (refl a : a = z)[z ⟼ a] we cannot conclude (refl a : a = z)[z ⟼ b], but we can conclude subs p (λx => a = x) (refl a) : a = b, which is not the result of a simple substitution from the hypothesis, as in ETT.
The rewrite tactic in Coq can fail - it can generate an ill-typed term.
If I remember correctly, it's sometimes possible to get around this with some careful manipulations, but if you do this by (implicitly or explicitly) introducing an additional axiom, such as functional extensionality or JMeq_eq, it's no longer the case that the first goal simply follows from the second.
Given a type (like List) in Coq, how do I figure out what the equality symbol "=" mean in that type? What commands should I type to figure out the definition?
The equality symbol is just special infix syntax for the eq predicate. Perhaps surprisingly, it is defined the same way for every type, and we can even ask Coq to print it for us:
Print eq.
(* Answer: *)
Inductive eq (A : Type) (x : A) : Prop :=
| eq_refl : eq x x.
This definition is so minimal that it might be hard to understand what is going on. Roughly speaking, it says that the most basic way to show that two expressions are equal is by reflexivity -- that is, when they are exactly the same. For instance, we can use eq_refl to prove that 5 = 5 or [4] = [4]:
Check eq_refl : 5 = 5.
Check eq_refl : [4] = [4].
There is more to this definition than meets the eye. First, Coq considers any two expressions that are equalivalent up to simplification to be equal. In these cases, we can use eq_refl to show that they are equal as well. For instance:
Check eq_refl : 2 + 2 = 4.
This works because Coq knows the definition of addition on the natural numbers and is able to mechanically simplify the expression 2 + 2 until it arrives at 4.
Furthermore, the above definition tells us how to use an equality to prove other facts. Because of the way inductive types work in Coq, we can show the following result:
eq_elim :
forall (A : Type) (x y : A),
x = y ->
forall (P : A -> Prop), P x -> P y
Paraphrasing, when two things are equal, any fact that holds of the first one also holds of the second one. This principle is roughly what Coq uses under the hood when you invoke the rewrite tactic.
Finally, equality interacts with other types in interesting ways. You asked what the definition of equality for list was. We can show that the following lemmas are valid:
forall A (x1 x2 : A) (l1 l2 : list A),
x1 :: l1 = x2 :: l2 -> x1 = x2 /\ l1 = l2
forall A (x : A) (l : list A),
x :: l <> nil.
In words:
if two nonempty lists are equal, then their heads and tails are equal;
a nonempty list is different from nil.
More generally, if T is an inductive type, we can show that:
if two expressions starting with the same constructor are equal, then their arguments are equal (that is, constructors are injective); and
two expressions starting with different constructors are always different (that is, different constructors are disjoint).
These facts are not, strictly speaking, part of the definition of equality, but rather consequences of the way inductive types work in Coq. Unfortunately, it doesn't work as well for other kinds of types in Coq; in particular, the notion of equality for functions in Coq is not very useful, unless you are willing to add extra axioms into the theory.
In Coq Tutorial, section 1.3.1 and 1.3.2, there are two elim applications:
The first one:
1 subgoal
A : Prop
B : Prop
C : Prop
H : A /\ B
============================
B /\ A
after applying elim H,
Coq < elim H.
1 subgoal
A : Prop
B : Prop
C : Prop
H : A /\ B
============================
A -> B -> B /\ A
The second one:
1 subgoal
H : A \/ B
============================
B \/ A
After applying elim H,
Coq < elim H.
2 subgoals
H : A \/ B
============================
A -> B \/ A
subgoal 2 is:
B -> B \/ A
There are three questions. First, in the second example, I don't understand what inference rule (or, logical identity) is applied to the goal to generate the two subgoals. It is clear to me for the first example, though.
The second question, according to the manual of Coq, elim is related to inductive types. Therefore, it appears that elim cannot be applied here at all, because I feel that there are no inductive types in the two examples (forgive me for not knowing the definition of inductive types). Why can elim be applied here?
Third, what does elim do in general? The two examples here don't show a common pattern for elim. The official manual seems to be designed for very advanced users, since they define a term upon several other terms that are defined by even more terms, and their language is ambiguous.
Thank you so much for answering!
Jian, first let me note that the manual is open source and available at https://github.com/coq/coq ; if you feel that the wording / definition order could be improved please open an issue there or feel free to submit a pull request.
Regarding your questions, I think you would benefit from reading some more comprehensive introduction to Coq such as "Coq'art", "Software Foundations" or "Programs and Proofs" among others.
In particular, the elim tactic tries to apply the so called "elimination principle" for a particular type. It is called elimination because in a sense, the rule allows you to "get rid" of that particular object, allowing you to continue on the proof [I recommend reading Dummett for a more throughout discussion of the origins of logical connectives]
In particular, the elimination rule for the ∨ connective is usually written by logicians as follows:
A B
⋮ ⋮
A ∨ B C C
────────────────
C
that is to say, if we can derive C independently from A and B, then we can derive it from A ∨ B. This looks obvious, doesn't it?
Going back to Coq, it turns out that this rule has a computational interpretation thanks to the "Curry-Howard-Kolmogorov" equivalence. In fact, Coq doesn't provide most of the standard logical connectives as a built in, but it allow us to define them by means of "Inductive" datatypes, similar to those in Haskell or OCaml.
In particular, the definition of ∨ is:
Inductive or (A B : Prop) : Prop :=
| or_introl : A -> A \/ B
| or_intror : B -> A \/ B
that is to say, or A B is the piece of data that either contains an A or a B, together with a "tag", that allows us to "match" to know which one do we really have.
Now, the "elimination principle for or" has type:
or_ind : forall A B P : Prop, (A -> P) -> (B -> P) -> A \/ B -> P
The great thing of Coq is that such principle is not a "built-in", just a regular program! Think, could you write the code of the or_ind function? I'll give you a hint:
Definition or_ind A B P (hA : A -> P) (hB : B -> P) (orW : A \/ B) :=
match orW with
| or_introl aW => ?
| or_intror bW => ?
end.
Once this function is defined, all that elim does, is to apply it, properly instantiating the variable P.
Exercise: solve your second example using apply and ord_ind instead of elim. Good luck!