New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mangle auto-generated names #6582
Conversation
98881fb
to
6264887
Compare
This is also somehow related to the discussion in #307. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain a bit more what is the use-case you envision for this kind of feature? I think I wouldn't like to work with it with an on-going development because the goal printing is obscured by this mangling:
Goal forall n m, n + m = m + n.
gets printed
1 subgoal
______________________________________(1/1)
forall _0 _1 : nat, _0 + _1 = _1 + _0
or
1 subgoal
______________________________________(1/1)
forall x0 x1 : nat, x0 + x1 = x1 + x0
with option:
Set Mangle Names Prefix "x".
So would this feature be a way to quickly fix a script that is suddenly failing because of names?
engine/namegen.ml
Outdated
@@ -190,9 +190,45 @@ let it_mkLambda_or_LetIn_name env sigma b hyps = | |||
(**********************************************************************) | |||
(* Fresh names *) | |||
|
|||
(* Introduce a mode where auto-generated names are mangled | |||
to test dependece of scripts on auto-generated names *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
The intent is that you first write your proofs with the option off, with the intent not to rely on auto-generated names. This part is the same as the current situation. That's how I was imagining this feature would be used. It's intended to be comparable to a linter. |
Thanks for the explanation. The use case is really interesting and I had completely missed it from the initial description. Now, reading it again I can see it was already sketched there but not as precisely. |
Is there any advantage to change the auto-generated identifier prefix rather than just appending an additional prefix to it? (To avoid the goals to become too obscure when debugging the use of an auto-generated name.) |
It's simpler (and being simpler here means less maintenance), it's independent of any changes in how default prefixes are chosen, it is easier to find short strings None of these are very significant considerations, and I did consider prepending instead. But I couldn't come up with a short generic default prefix that was likely to be unused. ( I'm definitely open to other algorithms proposed in light of the above. On the other hand, I am worried that the quadratic performance of generating new identifiers with the same prefix will be a noticeable problem. Prepending would address that issue. |
Isn't that patch breaking many scripts that rely on the half-specified behaviour of tactic-in-term naming strategy for bound variables? From the code it looks like |
Refine with binders still works. My patch gives Set Mangle Names.
Axiom x : Set.
Goal nat -> x.
refine (fun x => _).
(* 1 subgoal
x : nat
______________________________________(1/1)
Top.x *) (side note, I didn't know Ltac would fall back to the qualified name for the axiom This seems very robust behavior. If only all the introduction tactics ( By the way, we also have Set Mangle Names.
Goal nat -> Set -> Type.
refine (fun x x => _).
(* 1 subgoal
_1 : nat
x : Set
______________________________________(1/1)
Type *) (Why this is |
Hi, sorry to come late to the discussion, which is very interesting. In particular, I'm sympathetic to the idea of not preventing ourselves to possibly move to a radically new naming model, and to the idea that it may be the right time, after so many years of experience, for designing a "conceptual" model about names, capitalizing on this experience. I shall make some miscellaneous remarks, maybe some of them you will find commonplace, but, at least with the hope to suscitate further discussions or experimentations. I like very much the idea of cartouches, probably not as an exclusive approach, but as one of the possible ways to refer to an hypothesis (resting on a mathematical usage where one can refer to a statement or an hypothesis either by what it says, or by a reference, such as (*) or [3]). On the other side, I wonder how this scales to big proofs where we have many hypotheses with similar statement. I also consider I like the idea that a script should be invariant by the choice of generated names very much too. On the other side, it is comfortable not to think about names and to use the names offered by the system (and in particular, I think it is worth to teach Coq recipes to invent "nice" names, as I was trying to do with I regularly wonders whether things could be made simpler by having more powerful user interfaces. With user interfaces which know the structure of binders in a text and which are able to change all occurrences of the same name (its binding position and its bound occurrences) at the same time. With user interfaces which know in particular which names are generated and which are able to rename all occurrences of a generated name whenever a conflict arrive. Now, it is also the case that it is technically convenient to think at Coq as a tool which can be controlled textually. Otherwise said, how to drive such user interface features by requests to a core system. Thus, I believe that we strongly need to raise proof scripts at the level of an object of study, with a language to describe proof scripts, to describe bindings within a proof scripts, to describe dependencies, to apply transformations to proof scripts, as we do for proof terms but at a higher level (as was actually already contemplated in the good old Mowgli project with unibo). |
The behavior of abstract under this patch (mangling all hypothesis names in the context) is consistent with observable behavior (c.f. #3146); hypothesis names in the context can change inside abstract depending on the global environment. Thus this patch itself is working as intended. |
A few remarks:
Note that with something like cartouches you can do: rename < forall _:nat, _ < _ > into hyp3. and then use hyp3 if you like. That is more or less what you are describing.
The other choice (that I use) is to make name generation itself invariant to definition changes. I don't know which is better. I will definitively give a real try to cortouche.
It is not hard to implement something in IDEs that would help writing cortouche by clicking on a hypothesis (with some help from the prover I guess). That would not allow for refactoring but would make easy to write script that do not need refactoring. |
In response to the comment by @Zimmi48 about goal printing, that the names in goals are mangled says that printing (of the goals, at least Check as well, and probably other places) is asking for fresh names everywhere. For example
where I believe the name We could envision a different printing strategy, which renames as On the other hand, the Goal printing accurately reflects the names introduced by the plain Given the intended use as a linter, this shouldn't be a blocker for this PR. I'm working on rebasing and adding documentation; it should be ready for review after that. |
6264887
to
5968648
Compare
I rebased and added at least minimal documentation. I consider this ready for review by any interested parties. |
Second round at thinking at this PR: it is remarkably short for a pretty powerful feature. I wonder whether variants could be imagined. For instance, rather than having a On a related subject, I had a dream that a file translator could automatically make (most of) names which are generated explicit in existing scripts. Maybe one day. BTW, @jashug: did you make progress on #6781 or is it untractable? |
I started work on #6781, but got blocked on #6785, which caused for example
to fail, because the argument name |
So, you want to "mangle" not only proofs but statements? Alternatively, the "mangling" could give: |
No, I think that would be a step in the wrong direction. I think the implicit argument system should be changed so that if you ask for arguments named A and P, the default names are guaranteed to be A and P, where as currently you can get back e.x. A0 or _0. |
Currently, the default names of named/implicit arguments (the
This mangling option points this fact out, by changing the argument names to _0, _1, .... |
@jashug: thanks for your example (and for the pathological examples given at #6785). They obviously have to be fixed and there are certainly different possible remedies. To complete the picture, I can explain what was my motivation for using the name, say The typical (borderline) situation to address was typically the following: Definition a p := forall n, n+p=0.
Goal forall n, a n -> n=0.
unfold a.
(* forall n : nat, (forall n0 : nat, n0 + n = 0) -> n = 0 *)
intros.
(* n : nat H : forall n0 : nat, n0 + n = 0 |- n = 0 *)
apply H with (n0 := 0).
(* works *) To add to the zoo of pathological examples, I thought the following would have worked but it does not: Axiom b : forall p n, n + p = 0.
Goal forall n, n=0.
intros.
Check b.
(* forall p n : nat, n + p = 0 *)
Check b n.
(* forall n0 : nat, n0 + n = 0 *)
Fail apply (b n (n0:=0)).
(* Wrong argument name: n0. *)
Fail apply (b n (n:=0)).
(* Wrong argument name: n. *) |
There are no implicit arguments in the above, right? It looks like For example, the below works:
(Added |
Oh right, sorry. (So please see my message as only a parenthesis in the discussion.) |
For the record, I think this feature is the correct answer to the name generation problem. In particular, I'd definitely favour it by orders of magnitude over #268, which is trying to solve a slightly different but (IMO) unsolvable problem. |
This feature is ready basically, isn't it? It's just waiting for an approval. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For once, I'd be bold and support the merge the PR. It doesn't affect users if they're not using the option, and because it is typically used to make scripts more robust, it doesn't prevent us from changing the algorithm later to do something even more strict like e.g. generating purely random names.
@jashug Thanks a lot for this work! |
Kind: feature.
Related to #268, #2301.
RFC: Request For Comments
Tactic scripts relying on auto-generated names is a persistent problem.
It makes them more sensitive to
#268 attempts to address the problem by tracking which names are generated,
and emitting a warning when they are used (for some definitions of generated and used).
However, despite (from reading the comment logs) heroic work by @herbelin and everyone involved, #268 appears to have stalled.
This is a different approach to the same problem. We introduce an option that hijacks the name generation system to generate completely different names (
_0
,_1
,_2
, ... by default, in generalfoo0
,foo1
,foo2
, ... for user providedfoo
).Basically it's a variant of the approach in this comment.
I take a pretty broad view of what counts as a generated name, since many default names can be renamed to avoid shadowing names in the global/local context.
If instead the default was guaranteed to be the name you get, even if that shadows other names, then we could leave those as non-generated. (c.f. #6577)
I like to think of it as an emergency drill for having the name generation system radically change.
The intent is that development will proceed as usual, and after a proof is completed
you can either add
Set Mangle Names
in the file, or runcoqc
/coqide
with-mangle-names
.While
Set Mangle Names
is set, printing is also affected, butUnset Mangle Names
can be used to locally restore some nice names for printing.I think it is possible to write ltac such that it works both with and without
Set Mangle Names
. However, I believe that if youSet Mangle Names Prefix "foo"
for some identifier "foo" that doesn't appear as the prefix of any identifier in your development,then successful compilation ensures your script is immune to failures caused by changes in the environment or name generation system that cause unexpected renaming of your hypotheses.
(Failure due to tactics refusing to shadow are still plausible, again c.f. #6577)
Set Mangle Names Prefix "_"
gracefully