Search code examples
pattern-matchingcoqdependent-typeunificationreflect

Unification in pattern matching case


I was trying to write a function whose type is forall n, option (n = 1).

I choose option as an altertnative to reflect avoiding giving the proof of the negative case. So Some plays the role ReflectT and holds the proof, while None doesn't hold the negative proof.

Definition is_1 n: bool:=
  match n with
    1 => true |
    _ => false
  end.

Lemma is_1_complete : forall n, is_1 n = true -> n = 1.
intros.
destruct n. simpl in H. discriminate.
destruct n. reflexivity.
simpl in H. discriminate.
Qed.

Lemma a_nat_is_1_or_not: forall n, option (n = 1).
intros.
cut (is_1 n = true -> n = 1).
- 
intros.
destruct n. exact None.
destruct n. simpl in H. exact (Some (H (eq_refl))).
exact None.
-
exact (is_1_complete n).
Qed.

I've done with tactics. a_nat_is_1_or_not is the proof. And I thought I can do this writing the definition directly, so I tried.

Definition a_nat_is_1_or_not' n: option (n = 1) :=
  match is_1 n with
     true => Some (is_1_complete n eq_refl)
     | false => None
  end.

But Coq saids

Error:
In environment
n : nat
The term "eq_refl" has type "is_1 n = is_1 n"
while it is expected to have type "is_1 n = true" (cannot unify "is_1 n" and
"true").

It seems is_1 n cannot be unified to true in true case of the pattern matching of itself.

So I tried a more trivial example.

Definition every_true_is_I x: x = I :=
  match x with
     I => eq_refl
  end.

It works.

What is the difference between a_nat_is_1_or_not' and every_truer_is_I? Am I missing something? What can I do for writing a valid definition of forall n, is_1 n = true -> n = 1.?


Solution

  • The difference is that, in a_nat_is_1_or_not', you are depending on an external term whose type is is_1 n = true -> _. If you want a_nat_is_1_or_not' to look like every_true_is_I, you have to make sure that all the occurrences of is_1 n are covered by the pattern matching:

    Definition a_nat_is_1_or_not' n: option (n = 1) :=
      match is_1 n as b return ((b = true -> _) -> _) with
      | true => fun H => Some (H eq_refl)
      | false => fun _ => None
      end (is_1_complete n).
    

    Notice how is_1_complete has been instantiated outside the pattern matching, so that its occurrence of is_1 n (renamed b) is handled.

    There is another way to do it, perhaps a bit more idiomatic. Instead of generalizing the whole context, you just keep enough information to fill all the holes:

    Definition a_nat_is_1_or_not' n: option (n = 1) :=
      match is_1 n as b return (is_1 n = b -> _) with
      | true => fun H => Some (is_1_complete n H)
      | false => fun _ => None
      end eq_refl.
    

    But the idea is the same. By instantiating eq_refl outside the pattern matching, you do not lose any information when matching on is_1 n.