6

Often in Coq I find myself doing the following: I have the proof goal, for example:

some_constructor a c d = some_constructor b c d

And I really only need to prove a = b because everything else is identical anyway, so I do:

assert (a = b).

Then prove that subgoal, then

rewrite H.
reflexivity.

finishes the proof.

But it seems to just be unnecessary clutter to have those hanging around at the bottom of my proof.

Is there a general strategy in Coq for taking an equality of constructors and splitting it up into an equality of constructor parameters, kinda like a split but for equalities rather than conjunctions.

k_g
  • 4,333
  • 2
  • 25
  • 40

2 Answers2

4

You can use Coq's searching capabilities:

  Search (?X _ = ?X _).
  Search (_ _ = _ _).

Among some noise it reveals a lemma

f_equal: forall (A B : Type) (f : A -> B) (x y : A), x = y -> f x = f y

And its siblings for multi-argument equalities: f_equal2 ... f_equal5 (as of Coq version 8.4).

Here is an example:

Inductive silly : Set :=
  | some_constructor : nat -> nat -> nat -> silly
  | another_constructor : nat -> nat -> silly.

Goal forall x y,
    x = 42 ->
    y = 6 * 7 ->
    some_constructor x 0 1 = some_constructor y 0 1.
  intros x y Hx Hy.
  apply f_equal3; try reflexivity.

At this point all you need to prove is x = y.

Anton Trunov
  • 15,074
  • 2
  • 23
  • 43
  • 1
    Yes, constructors are injective functions, that's why this approach will always work. And `f_equal` can be applied to every injective function. There is also a tactic `injection` which works on *hypotheses*. There is more information [here](http://adam.chlipala.net/itp/tactic-reference.html). – Anton Trunov May 27 '16 at 20:05
  • I do not understand why it is important that constructors are injective functions for `f_equal` to work. Note also that you are not forced to use `f_equal3` here, and that `apply (f_equal (fun k => some_constructor k 0 1)).` works. – eponier May 28 '16 at 21:31
  • @eponier Of course, `f_equal` may be applied to any equality of relevant form. But if a function is injective, it guarantees you don't throw away information (which you'd be useful later). For example, `Goal Z.abs 1 = Z.abs (-1). apply f_equal.` "works", but leaves you with `1 = -1` as the goal, because `Z.abs` is obviously not injective. – Anton Trunov May 28 '16 at 21:57
  • I'm with eponier here, injective means `f x = f y -> x = y`, whereas the original question is `x = y -> f x = f y`. – ejgallego May 28 '16 at 23:06
  • @ejgallego Yes, that's exactly right. If `f` (it's `some_constructor` in the OP) is injective, one can *always* apply `f_equal` to prove the goal, because of the injectivity condition you've mentioned above. That is not the case in general for an arbitrary function (as I've shown in my prev. comment). Upshot: I was talking about a sufficient condition, not a necessary one. – Anton Trunov May 29 '16 at 08:24
  • @AntonTrunov, umm, I'm not sure this is true. For instance, to prove `S 3 = S 4` from the proper hypothesis, applying `f_equal` is an unnecessary step. – ejgallego May 29 '16 at 10:28
  • @ejgallego Good point, but I didn't say that we always *have* to do it ;) – Anton Trunov May 29 '16 at 16:16
3

In particular, standard Coq provides the f_equal tactic.

Inductive u : Type := U : nat -> nat -> nat -> u.

Lemma U1 x y z1 z2 : U x y z1 = U x y z2.
f_equal

Also, ssreflect provides a general-purpose congruence tactic congr.

ejgallego
  • 6,709
  • 1
  • 14
  • 29
  • It seems to me that the tactic `f_equal` often produces more complicated terms than just `apply f_equal`. – eponier May 28 '16 at 21:33