Another answer focuses on the discriminate part, I will focus on the manual proof. You tried:
Lemma l2: A=B -> False.
apply (fun e:(A=B) => match e with end).
Defined.
What should be noted and makes me often uncomfortable using Coq is that Coq accepts ill-defined definitions that it internally rewrites into well-typed terms. This allows to be less verbose, since Coq adds itself some parts. But on the other hand, Coq manipulates a different term than the one we entered.
This is the case for your proof. Naturally, the pattern-matching on e
should involve the constructor eq_refl
which is the single constructor of the eq
type. Here, Coq detects that the equality is not inhabited and thus understands how to modify your code, but what you entered is not a proper pattern-matching.
Two ingredients can help understand what is going on here:
- the definition of
eq
- the full pattern-matching syntax, with
as
, in
and return
terms
First, we can look at the definition of eq
.
Inductive eq {A : Type} (x : A) : A -> Prop := eq_refl : x = x.
Note that this definition is different from the one that seems more natural (in any case, more symmetric).
Inductive eq {A : Type} : A -> A -> Prop := eq_refl : forall (x:A), x = x.
This is really important that eq
is defined with the first definition and not the second. In particular, for our problem, what is important is that, in x = y
, x
is a parameter while y
is an index. That is to say, x
is constant across all the constructors while y
can be different in each constructor. You have the same difference with the type Vector.t
. The type of the elements of a vector will not change if you add an element, that's why it is implemented as a parameter. Its size, however, can change, that's why it is implemented as an index.
Now, let us look at the extended pattern-matching syntax. I give here a very brief explanation of what I have understood. Do not hesitate to look at the reference manual for safer information. The return
clause can help specify a return type that will be different for each branch. That clause can use the variables defined in the as
and in
clauses of the pattern-matching, which binds respectively the matched term and the type indices. The return
clause will both be interpreted in the context of each branch, substituting the variables of as
and in
using this context, to type-check the branches one by one, and be used to type the match
from an external point of view.
Here is a contrived example with an as
clause:
Definition test n :=
match n as n0 return (match n0 with | 0 => nat | S _ => bool end) with
| 0 => 17
| _ => true
end.
Depending on the value of n
, we are not returning the same type. The type of test
is forall n : nat, match n with | 0 => nat | S _ => bool end
. But when Coq can decide in which case of the match we are, it can simplify the type. For example:
Definition test2 n : bool := test (S n).
Here, Coq knows that, whatever is n
, S n
given to test
will result as something of type bool
.
For equality, we can do something similar, this time using the in
clause.
Definition test3 (e:A=B) : False :=
match e in (_ = c) return (match c with | B => False | _ => True end) with
| eq_refl => I
end.
What's going on here ? Essentially, Coq type-checks separately the branches of the match
and the match
itself. In the only branch eq_refl
, c
is equal to A
(because of the definition of eq_refl
which instantiates the index with the same value as the parameter), therefore we claimed we returned some value of type True
, here I
. But when seen from an external point of view, c
is equal to B
(because e
is of type A=B
), and this time the return
clause claims that the match
returns some value of type False
. We use here the capability of Coq to simplify pattern-matching in types that we have just seen with test2
. Note that we used True
in the other cases than B
, but we don't need True
in particular. We only need some inhabited type, such that we can return something in the eq_refl
branch.
Going back to the strange term produced by Coq, the method used by Coq does something similar, but on this example, certainly more complicated. In particular, Coq often uses types IDProp
inhabited by idProp
when it needs useless types and terms. They correspond to True
and I
used just above.
Finally, I give the link of a discussion on coq-club that really helped me understand how extended pattern-matching is typed in Coq.