Why don't the remember tactics work as documented? - coq

In an interactive proof, I'm trying to extract an expression into a new variable while capturing the equality as a new proof term.
The remember tactic seems designed for this purpose. Since I like giving explicit names to introduced names, I'd prefer to use this variant:
remember term as ident eqn:ident
This behaves as remember term as ident, except that the name of the generated equality is also given.
However when I attempt it (or the other remember variants), I only get this error:
> remember (prefix ++ suffix) as the_environment eqn:H_prefix_suffix.
> ^^^
Syntax error: 'in' '|-' expected after [prim:ident] (in [tactic:simple_tactic]).
Heeding the error message, the only variant that actually seems to work is
remember (prefix ++ suffix) as the_environment in |-.
...which unfortunately doesn't let me choose the name of the introduced proof of equality.
Why don't the documented remember variants seem to work?
I'm using coq 8.4pl6.

I shot myself in the foot.
I had previously declared a tactic with that syntax:
Tactic Notation "remember" constr(c) "as" ident(x) "in" "|-" :=
let x := fresh x in
let H := fresh "Heq" x in
(set (x := c); assert (H : x = c) by reflexivity; clearbody x).
It seems this explicit definition masks the built-in variants. Removing this definition makes the others visible again.

Related

What is the difference between definitions and theorems?

In the current version of the Software Foundations, the relevant explanation is formulated with intentional leeway.
First, we've used the keyword Theorem instead of Example.
This difference is mostly a matter of style; the keywords
Example and Theorem (and a few others, including Lemma,
Fact, and Remark) mean pretty much the same thing to Coq.
(I put the wording used to introduce uncertainty in bold.)
In an earlier version of, evidently, the same writing, it was put strongly:
The form of this theorem and proof are almost exactly the same as the examples above: the only differences are that we've added the quantifier ∀ n:nat and that we've used the keyword Theorem instead of Example. Indeed, the latter difference is purely a matter of style; the keywords Example and Theorem (and a few others, including Lemma, Fact, and Remark) mean exactly the same thing to Coq.
(I put words introducing strength in bold.)
Looking at the official documentation, all of these words, and more, belong to the same grammatical category «assertion keyword»:
assertion_keyword ::= Theorem | Lemma
Remark | Fact
Corollary | Property | Proposition
Definition | Example
There are further two sections explaining how these keywords work: «Definitions» and «Assertions and proofs». In short:
Definitions extend the environment with associations of names to terms.
— And:
An assertion states a proposition (or a type) of which the proof (or an inhabitant of the type) is interactively built using tactics.
But, as far as I see, a theorem also extends the environment, and an example can be built with tactics. So, I am not seeing where these things are different. But the Software Foundation is a clever book. If they chose to be uncertain, there must be a reason?
As of today the differences are minimal, and could be summarized as:
Theorem/Example/Definition/... do produce different entries in the documentation; this is the most relevant difference.
Some forms such as Theorem don't support the syntactical form Theorem foo := nat. for non-interactive mode, which is supported by Definition for example.
Another non-trivial difference is whether you use the interactive mode or not. That is to say:
Definition foo : Type := nat.
and
Definition foo : Type. Proof. apply nat. Qed.
will take slightly different code paths due to the second creating an interactive proof; the codepath when the definition gets sent to the kernel is a bit different, but Coq 8.12 should unify them for all practical purposes, just marking the second proof as opaque.
One difference I've seen is that Definitions can give an immediate definition, whereas Lemma and Theorem can't.
Definition one := 1.
Lemma two := 2. (* syntax error *)
Theorem three := 3. (* syntax error *)
Out of the rest, only Example works.
Remark four := 4. (* syntax error *)
Fact five := 5. (* syntax error *)
Corollary six := 6. (* syntax error *)
Property seven := 7. (* syntax error *)
Proposition eight := 8. (* syntax error *)
Example nine := 9. (* works! *)

Tactics with variable arity

Say I want to have a tactic to clear multiple hypothesis at once, to do something like clear_multiple H1, H2, H3.. I tried to do that using pairs, like the following:
Ltac clear_multiple arg :=
match arg with
| (?f, ?s) => clear s; clear_multiple f
| ?f => clear f
end.
But then, the problem is that I have to place parenthesis to have a Prod:
Variable A: Prop.
Goal A -> A -> A -> True.
intros.
clear_multiple (H, H0, H1).
My question is, how to do that without using Prods ?
I checked this question, but it is not exactly what I want, since the number of arguments I want is not known.
You might like to know that the clear tactic can take multiple arguments, so you do not need to define a new tactic: you can just write clear H H0 H1.
Of course, you might want to define such n-ary tactics for other tasks. Coq has a tactic notation mechanism that supports such definitions. Unfortunately, they are not too powerful: you can only pass a list of arguments of a certain kind to a tactic that expects multiple arguments (like clear); I don't think it can give you a list that you can iterate on programmatically.

Definition vs Notation for constants

I'm extending an existing project (Featherweight Java formalization),
and there are a number of constants, such as:
Notation env := (list (var * typ)).
What would change if I used Definition instead:
Definition env := (list (var * typ)).
Why did the author use Notation here?
Whenever you try to apply or rewrite with a lemma, there's a component in Coq called the unifier that tries to find out how to instantiate your lemma so that it can work with the situation at hand (and checking that it indeed applies there). The behavior of this unifier is a bit different depending on whether you use notations or definitions.
Notations are invisible to Coq's theory: they only affect the parsing and printing behavior of the system. In particular, the unifier doesn't need to explicitly unfold a notation when analyzing a term. Definitions, on the other hand, must be explicitly unfolded by the unifier. The problem is that the unifier works heuristically, and cannot tell with 100% certainty when some definition must be unfolded or not. As a consequence, we often find ourselves with a goal that mentions a definition that the unifier doesn't unfold by itself, preventing us from applying a lemma or rewriting, and having to manually add a call to unfold ourselves to get it to work.
Thus, notations can be used as a hack to help the unifier understand what an abbreviation means without manual unfolding steps.

when is the `:` (colon) in necessary in ssreflect/Coq?

I am trying to understand the exact meaning of the : (colon) in Coq/ssreflect proofs in terms of non-ssreflect Coq.
I read that it has something to do with moving things to the goal (like generalize??) and is the opposite of =>, which move things to the hypotheses. However, I often find it confusing because proofs work either way with or without the :. Below is an example from a tutorial:
Lemma tmirror_leaf2 t : tmirror (tmirror t) = Leaf -> t = Leaf.
Proof.
move=> e.
by apply: (tmirror_leaf (tmirror_leaf e)).
Qed.
where,
tmirror_leaf
: forall t, tmirror t = Leaf -> t = Leaf
is a lemma that says if the mirror of a tree is a leaf, then the tree is a leaf.
I don't understand why we need the : here and not merely do the Coq apply. In fact, if I remove the :, it works just fine. Why does it make a difference?
Indeed, apply: H1 ... Hn is to all effects equivalent to move: H1 .. Hn; apply. A more interesting use of apply is apply/H and its variations, which can interpret views.
I think I found the answer while reading the SSReflect documentation. Essentially, ssr has redefined tactics like apply such that it operates on the first variable of the goal instead of something in the context. That's why the : is used in apply: XX. in the ssr way (which is equivalent to move: XX; apply.), and it also works if : is omitted as that is the traditional Coq way.
Quoting the documentation:
Furthermore, SSReflect redefines the basic Coq tactics case, elim, and
apply so that they can take better advantage of ':' and '=>'. These
Coq tactics require an argument from the context but operate on the
goal. Their SSReflect counterparts use the first variable or constant
of the goal instead, so they are "purely deductive":
they do not use or change the proof context. There is no loss since
`:' can readily be used to supply the required variable.

how to name the assumption when remembering an expression?

The documentation for Coq carries the general admonition not to rely on the builtin naming mechanism, but select one's own names, lest the changes in the naming mechanism render past proofs invalid.
When considering expressions of the form remember Expr as v, we set the variable v to the expression Expr. But the name of the assumption is selected automatically, and is something like Heqv, so we have:
Heqv: v = Expr
How can I select my own name instead of Heqv? I can always rename it to whatever I like using the rename command, but that doesn't keep my proofs independent of the hypothetical future changes in the builtin naming mechanism in Coq.
If you may get rid of the separate equality, try set (name := val). Use unfold instead of rewrite to get the value back in place.
If you need the equality for more than the rewrite <-, I know of no built in tactic that does this. You can do it manually, though, or build a tactic / notation. I just threw this together. (Note: I'm not an expert, this might be done more easily.)
Tactic Notation "remember_as_eq" constr(expr) ident(vname) ident(eqname) :=
let v := fresh in
let HHelp := fresh in
set (v := expr);
(assert (HHelp : sigT (fun x => x = v)) by ( apply (existT _ v); reflexivity));
inversion HHelp as [vname eqname];
unfold v in *; clear v HHelp;
rewrite <- eqname in *.
Use as remember_as_eq (2+2) four Heqfour to get the same result as with remember (2+2) as four.
Note: Updated to handle more cases, the old version failed on some combinations of value and goal type. Leave a comment if you find another case that works with rewrite but not this one.