1

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?

Lorenz
  • 1,263
  • 9
  • 20

1 Answers1

2

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.
gallais
  • 11,823
  • 2
  • 30
  • 63
  • 3
    There is also syntactic sugar for the case when constructors are coercions: `Inductive exp: Set := | CE :> nat -> exp.` automatically declares `CE` as a coercion (notice that I used `:>` instead of `:` for `CE`). – Anton Trunov Aug 03 '17 at 15:33
  • Thank you, these are both very elegant solutions and clearly preferable to what I used in the question. In my specific situation though, I have to solve homework assignments and have to work with data type definitions and coercions provided by my lecturer. Changing these definitions is not an option. I think I will just use additional branches in the tactic for the coercions. – Lorenz Aug 03 '17 at 17:10
  • 1
    @frececroka You can also use e.g. `cbv delta.` before pattern-matching on the goal to unfold transparent definitions. Then your original `my_tactic` would work. – Anton Trunov Aug 04 '17 at 13:24