Skip to content
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

over tactic fails after rewrite #11118

Open
mrhaandi opened this issue Nov 14, 2019 · 13 comments · May be fixed by #19011
Open

over tactic fails after rewrite #11118

mrhaandi opened this issue Nov 14, 2019 · 13 comments · May be fixed by #19011
Labels
kind: bug An error, flaw, fault or unintended behaviour. part: ssreflect The SSReflect proof language.

Comments

@mrhaandi
Copy link
Contributor

Description of the problem

Reading the documentation of the under/over tactics, the following Lemmas works and fails should be equivalent. However, after under, a rewrite causes over to fail saying "No applicable tactic.".
Maybe, the rewrite also changes something that is supposed to be hidden behind the scenes.

Require Import ssreflect ssrbool ssrfun.
Require Import List.

Lemma works (A: list (nat * nat)) (f: nat -> nat): 
  map (fun (a: nat * nat) => fst (let '(x, y) := a in (f x, f y))) A = map (fun (a: nat * nat) => f (fst a)) A.
Proof.
  rewrite (map_ext _ (fun (a: nat * nat) => f (fst a))).
    move=> a. rewrite (surjective_pairing a). done.
  done.
Qed.

Lemma fails (A: list (nat * nat)) (f: nat -> nat): 
  map (fun (a: nat * nat) => fst (let '(x, y) := a in (f x, f y))) A = map (fun (a: nat * nat) => f (fst a)) A.
Proof.
  under map_ext.
    move=> a. rewrite (surjective_pairing a). over. (* fails: "No applicable tactic." *)
  done.
Admitted.

Coq Version

8.10.1

@gares
Copy link
Member

gares commented Nov 14, 2019

CC @erikmd

@erikmd
Copy link
Member

erikmd commented Nov 14, 2019

Dear @mrhaandi, thanks for the question. Indeed, the issue you observe comes from the fact rewrite (surjective_pairing a) (in your second example) unexpectedly rewrites the hidden evar, which subsequently prevents the over tactic to instantiate it:

Lemma fails (A: list (nat * nat)) (f: nat -> nat): 
  map (fun (a: nat * nat) => fst (let '(x, y) := a in (f x, f y))) A = map (fun (a: nat * nat) => f (fst a)) A.
Proof.
under map_ext.
  move=> a.

  Set Printing All.
  (* @Under_eq nat (…) (?Goal a) *)

  rewrite (surjective_pairing a).
  (*  @Under_eq nat (…) (?Goal (@pair nat nat (@fst nat nat a) (@snd nat nat a))) *)

So to fix you proof script, I'll suggest you just do

under map_ext.
  move=> a. rewrite {1}(surjective_pairing a). over.

or more succinctly:

under map_ext => a.
  by rewrite {1}(surjective_pairing a) over.

@mrhaandi
Copy link
Contributor Author

I see, thank you @erikmd .
However, for more complex examples it is tedious to figure out the particular occurrences.
For now, I have a workaround (see below) based on the contextual pattern in Under_eq _ that seems to select the right occurrences.

Lemma workaround (A: list (nat * nat)) (f: nat -> nat): 
  map (fun (a: nat * nat) => fst (let '(x, y) := a in (f x, f y))) A = map (fun (a: nat * nat) => f (fst a)) A.
Proof.
  under map_ext.
    move=> a. rewrite [in Under_eq _] (surjective_pairing a). over.
  done.
Qed.

Since Under_eq itself is supposed to be hidden, this workaround still feels hacky.

@gares
Copy link
Member

gares commented Nov 15, 2019

Erik, I don't get why the evar that was touched by rewrite cannot be instantiated. Isn't it a weakness of reflexivity (unification)?

@gares
Copy link
Member

gares commented Nov 15, 2019

I don't mind hardwiring in the pattern selection algorithm a blacklist for the last argument of under_eq, I think it is a feature of more general interest, but I want to understand what fails precisely.

@gares
Copy link
Member

gares commented Nov 15, 2019

In the meantime I suggest you use the pattern, you can also do as for LHS, see bigop.v, to define a shorthand. If you are consistent then porting your scripts to a fixed version of SSR can be done with a simple search/replace.

@erikmd
Copy link
Member

erikmd commented Nov 15, 2019

@mrhaandi

Since Under_eq itself is supposed to be hidden, this workaround still feels hacky.

Yes, and BTW Under_eq will be replaced with Under_rel in the upcoming 8.11, cf. #10022

@gares

Erik, I don't get why the evar that was touched by rewrite cannot be instantiated. Isn't it a weakness of reflexivity (unification)?

No, this occurs precisely because the lemma that is rewritten here falls in the following corner case:
it has type a = (a.1, a.2), so it applies to all occurrences of bound variable a, including (?Goal a) … and this rewrite is precisely what we wouldn't want in practice.

I don't mind hardwiring in the pattern selection algorithm a blacklist for the last argument of Under_eq, I think it is a feature of more general interest,

Sounds a good idea 👍 (I don't see other solutions apart from that and the use of an occurrence selector / contextual pattern)

@erikmd erikmd added kind: bug An error, flaw, fault or unintended behaviour. part: ssreflect The SSReflect proof language. labels Nov 26, 2019
@erikmd
Copy link
Member

erikmd commented Nov 26, 2019

Hi @gares

I don't mind hardwiring in the pattern selection algorithm a blacklist for the last argument of under_eq,

IINM that blacklisting for Under_rel should be implemented in plugins/ssrmatching/ssrmatching.ml

can you have a look in the upcoming days? (I'd be willing to help if need be, but I am not familiar with the pattern selection algo implemented in that file;
and I don't know if it should be kept possible to bypass that hardwired blacklisting for Under_eq/Under_rel, e.g. by doing rewrite [in X in @Under_eq _ _ X]lem?)

(reminder: Under_eq is the "tag" for Coq 8.10, and Under_rel for Coq 8.11)

@gares
Copy link
Member

gares commented Nov 27, 2019

I'm sorry but I'm a bit busy. What I had in mind is to have in ssrmatching.v a transparent polymorphic identity function called nomatch, Registered as ssr.nomatch and have the first two terms to which it is applied be ignored by these pieces of code:

let f, a = splay_app ise c in let i0 = ref (-1) in

let f, a = splay_app ise c in let i0 = ref (-1) in

let f, a = splay_app sigma c' in

There we look at the head constant of a subterm of the goal, and do stuff. If that f is the special identity, then we should skip things accordingly.

Then under generates the goal Under_rel T LHS (nomatch T RHS) and that is all.

@gares
Copy link
Member

gares commented Nov 27, 2019

the first two terms

This is to deal with the corner case nomatch (T1 -> T2) f t that should not protect t. Such a term can be, in principle, obtained by applying other tactics if we start using nomatch elsewhere. It should not happen in the case of under I believe.

@gares
Copy link
Member

gares commented Nov 27, 2019

FTR, this feature should be documented next to lock, since it is serves similar purposes, but has no logical effect (while lock t =/= t, and indeed one can use lock to decorate the head of an application, so that matching does not recognize it, but it does not prevent matching to recurse under it).

@erikmd
Copy link
Member

erikmd commented Nov 27, 2019

Thanks @gares for your comments!

A question on a detail:

this feature should be documented next to lock

you seem to suggest here to add the nomatch function in ssreflect.v, but as this change deals with ssrmatching.ml, shouldn't this be added to ssrmatching.v ?

@gares
Copy link
Member

gares commented Nov 27, 2019

Sure, I think I'd be fine with a See also...

erikmd added a commit to erikmd/coq that referenced this issue Nov 27, 2019
@erikmd erikmd linked a pull request May 8, 2024 that will close this issue
3 tasks
erikmd added a commit to erikmd/coq that referenced this issue May 8, 2024
erikmd added a commit to erikmd/coq that referenced this issue May 8, 2024
erikmd added a commit to erikmd/coq that referenced this issue May 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: bug An error, flaw, fault or unintended behaviour. part: ssreflect The SSReflect proof language.
Projects
None yet
3 participants