coq / coq

Coq is a formal proof management system. It provides a formal language to write mathematical definitions, executable algorithms and theorems together with an environment for semi-interactive development of machine-checked proofs.
https://coq.inria.fr/
GNU Lesser General Public License v2.1
4.84k stars 646 forks source link

When is it better or not to clear by default a variable used by a tactic? #13525

Open herbelin opened 3 years ago

herbelin commented 3 years ago

Description of the problem

The rules for clearing or not by default the argument of a tactic when it is a variable are undocumented and a bit unclear.

For destruct/induction, the variable is cleared by default when there is no with or eqn clause or in clause and it is the e-variant of them. The restriction to eqn or in is obvious because a dependency remains but the restriction to edestruct/einduction and with is however unclear (see in particular #13521). Note that there is a syntax to cancel the clearing when it is the default: it is to surround the variable with parentheses, e.g. destruct (n).

For apply/rewrite, the variable is not cleared by default (when it is a variable). The practice would suggest that it is however more common to use an hypothesis once than more than once. So a clearing by default could be a convenient default. Note that there is an undocumented syntax to force clearing, namely apply >H or rewrite >H.

SkySkimmer commented 3 years ago

With destruct/induction it seems there is a guarantee that there is no remaining dependency on the variable? For instance if you try

Lemma foo X (x:X) (e:x=x) (H:e = eq_refl) : False.
  destruct e.

it will fail rather than doing some sort of dummy match, and in succesful cases the variable would get replaced by the appropriate constructor application. Maybe I missed an edge case though?

With apply/rewrite clearly there is no guarantee, IMO if we have to analyse whether there is a dependency to be able to decide if we're clearing we just shouldn't clear. I guess the alternative is to force clear by default, failing if there is a dependency, with a syntax to skip clearing, but that feels somewhat strange to me.

herbelin commented 3 years ago

I see three typical cases:

@SkySkimmer, your example fails but the failure is not a guarantee that a non failure of destruct x with x of inductive type is w/o loss of information. Consider e.g. Lemma foo (x:nat) (e:x = S x) : x = x. destruct e. which works but loses the information that there is a contradiction.

It seems that my question is about the "other irreversible steps". Assuming that we give a modifier to force a clear or to prevent a clear when the default is not what is expected, what is the most useful default, to clear or not to clear? That is, is it more common to use resources linearly or not?

[Added] More precisely, it seems to me that either those apply and rewrite of the third category should clear by default, or those destruct of the third category should not clear (disregarding questions of compatibility).

SkySkimmer commented 3 years ago

I don't care about reversibility tbh, it seems like the wrong thing to look at.