Search code examples
coqcoq-tacticltac

Coq coercions and goal matching


Assume I have the following setup:

Inductive exp: Set :=
| CE: nat -> exp.

Inductive adt: exp -> Prop :=
| CA: forall e, adt e.

Coercion nat_to_exp := CE.

Ltac my_tactic := match goal with
| [ |- adt (CE ?N) ] => apply (CA (CE N))
end.

And I try to prove a simple theorem using the custom tactic:

Theorem silly: adt 0.
Proof.
  my_tactic. (* Error: No matching clauses for match. *)
Abort.

This fails, because the goal is not of the form adt (CE ?N) but of the form adt (nat_to_exp ?N) (This is shown explicitly when using Set Printing Coercions).

Trying to prove a slightly different theorem works:

Theorem silly: adt (CE 0).
Proof.
  my_tactic. (* Success. *)
Qed.

Possible workarounds I know of:

  • Not using coercions.
  • Unfolding coercions in the tactic (with unfold nat_to_exp). This alleviates the problem slightly, but fails as soon as a new coercion is introduced the tactic doesn't know about.

Ideally, I would like the pattern matching to succeed if the pattern matches after unfolding all definitions (The definitions should not stay unfolded, of course).

Is this possible? If not, are there reasons why it is not possible?


Solution

  • You can directly declare the constructor CE as a coercion rather than wrapping it as nat_to_exp like so:

    Coercion CE : nat >-> exp.
    

    The proof then goes through without any issue. If you insist on naming your coercion (e.g. because it's a compound expression rather than a single constructor), you can change your tactics so that it handles non unfolded coercions explicitly:

    Ltac my_tactic := match goal with
    | [ |- adt (CE ?N) ] => apply (CA (CE N))
    | [ |- adt (nat_to_exp ?N) ] => apply (CA (CE N))
    end.