Zulip Chat Archive

Stream: general

Topic: How to apply at a hypothesis/assumtption?


Viliam Vadocz (Jun 26 2024 at 19:34):

Hi, beginner question:

I have hypothesis h: p and I want to apply not_not.mpr to get \not \not p. When I true by apply not_not.mpr at h, I get unexpected token 'at'. How do I use the apply tactic at a hypothesis?

Ruben Van de Velde (Jun 26 2024 at 19:35):

Please provide a #mwe

Viliam Vadocz (Jun 26 2024 at 19:37):

@Ruben Van de Velde

open Classical

example (p : Prop) : ¬p :=
  by
  intro h
  apply not_not.mpr at h
  sorry

Obviously, this is impossible to prove, but it shows the error.

Henrik Böving (Jun 26 2024 at 19:40):

What you are trying to do here is called forward reasoning, this is not what apply is for, apply is for backwards reasoning. What this means is that if you have a goal Q and a lemma P -> Q then applying that lemma changes your goal to P. What you can do for example is use have h2 := not_not.mpr h or if you wish to get rid of h: replace h := not_not.mpr h Note that you can optionally specifiy a type annotation like so: have name : type := proof

Ruben Van de Velde (Jun 26 2024 at 19:42):

It works if you add import Mathlib, though

Viliam Vadocz (Jun 26 2024 at 19:42):

Thanks, that answers my question.

Shreyas Srinivas (Jun 26 2024 at 19:52):

Henrik: I recall a few months ago Kevin asked for forward reasoning with apply on hypothesis and this was added

Henrik Böving (Jun 26 2024 at 19:53):

Added to Mathlib it seems yeah, I don't keep up with the tactics that are developed there as much.

Shreyas Srinivas (Jun 26 2024 at 19:53):

But I really dislike the way it works because it intuitively renames the wrong hypothesis

Shreyas Srinivas (Jun 26 2024 at 19:53):

I just use replace or specialize

Shreyas Srinivas (Jun 26 2024 at 19:55):

specialize is way more intuitive than apply at because I am clearly just instantiating a general hypothesis with specific parameters

Kevin Buzzard (Jun 26 2024 at 23:08):

Hoards of mathematicians disagree with you. In fact I'm surprised you don't find it intuitive -- mathematicians find apply at very intuitive, this is a standard step for them. In contrast they find apply extremely unintuitive. I know this from lots of NNG feedback.

Shreyas Srinivas (Jun 26 2024 at 23:12):

Kevin I don't find the normal apply on a goal unintuitive. But if I have a hypothesis ha : a and hab : a -> b then apply hab at ha leaves me with ha : b.

Shreyas Srinivas (Jun 26 2024 at 23:12):

This messes with my naming scheme

Shreyas Srinivas (Jun 26 2024 at 23:13):

whereas if it was hab : b I would be less confused because now I have applied the specific argument ha and now I have the specialized hypothesis

Shreyas Srinivas (Jun 26 2024 at 23:13):

See the states below:

import Mathlib

example (a b : Prop) (ha : a) (hab : a  b) : b := by
  apply hab at ha -- see state here

example (a b : Prop) (ha : a) (hab : a  b) : b := by
  specialize hab ha  -- see state here

Shreyas Srinivas (Jun 26 2024 at 23:14):

I assure you I am a novice at this type theory business.

Shreyas Srinivas (Jun 26 2024 at 23:17):

specialize is just applying a function to its arguments. That's easy.

Kevin Buzzard (Jun 26 2024 at 23:23):

I see your point!

Shreyas Srinivas (Jun 26 2024 at 23:25):

I would find it more intuitive if the syntax was apply ha at hab and this changed
hab : a -> b to hab : b

Kevin Buzzard (Jun 26 2024 at 23:26):

Yes, this was the point I got from your messages.

Shreyas Srinivas (Jun 26 2024 at 23:27):

Is it really worth it to change this behaviour for all those NNG users and confuse them when I can use specialize and apply a full sequence of arguments at a hypothesis instead of using apply?

Shreyas Srinivas (Jun 26 2024 at 23:28):

I haven't heard anybody else complain about this

Shreyas Srinivas (Jun 26 2024 at 23:31):

Here's a quick and dirty version of this change with examples

import Mathlib

macro "apply " t:term " at " h:term :tactic => do
  `(tactic| specialize $h $t)

example (a b c : Prop) (ha : a) (hb : b) (hab : a  b  c) : c := by
  specialize hab ha hb -- see state here

example (a b c : Prop) (ha : a) (hb : b) (hab : a  b  c) : c := by
  apply ha at hab
  apply hb at hab

Shreyas Srinivas (Jun 26 2024 at 23:32):

specialize clearly has a brevity advantage

Kevin Buzzard (Jun 26 2024 at 23:43):

The issue I guess is that mathematicians don't tend to think of a proof as a function and in NNG4 we try to move away from that idea.

Shreyas Srinivas (Jun 26 2024 at 23:47):

If you like the behaviour of apply at that I show above, then I can make a PR to change it. Or we could do a poll. I am skeptical of making changes to tutorial relevant tactics when I don't see anybody else complaining about it or expressing opinions

Kevin Buzzard (Jun 26 2024 at 23:48):

Yeah I removed the suggestion to PR a change about 30 seconds after suggesting it but it seems you saw it anyway :-)

Shreyas Srinivas (Jun 26 2024 at 23:49):

I prefer my version of apply at even more for longer chains of implications or \foralls because I consistently retain one name for the hypothesis (in this case hab) that I am moving forward on.

Shreyas Srinivas (Jun 26 2024 at 23:49):

otherwise it is a confusing mess of names, which are both hard to find in the infoview when writing big proofs and look confusing in the proof script once the proof is done.

Mario Carneiro (Jun 26 2024 at 23:53):

I think it is better to keep them as they are. apply hab at ha renames ha to the result, specialize hab ha renames hab to the result, both might be useful depending on context

Mario Carneiro (Jun 26 2024 at 23:54):

I think the motivation for the apply at behavior is that hab may not be a variable in the context at all but rather a global theorem, in which case renaming it doesn't make sense

Mario Carneiro (Jun 26 2024 at 23:54):

also at h generally names a hypothesis in the context that may be rewritten

Shreyas Srinivas (Jun 26 2024 at 23:58):

That makes sense. I think I would find apply at less painful if the hypothesis didn't move around in the proof state. In a large proof it's like playing hide and seek with my hypotheses. Not moving the hypotheses around would still mess with my naming scheme but at least I won't lose track of the name change so easily. But again that could just be me and people might prefer seeing the latest hypothesis they are working on appear closer to the goal

Shreyas Srinivas (Jun 26 2024 at 23:58):

Anyway, I am happy with specialize so this is more or less a non-issue for me.

Shreyas Srinivas (Jun 27 2024 at 15:12):

Slightly related to what you mentioned @Mario Carneiro : Is there a tactic that just introduces a global theorem into the list of local hypothesis. Technically it's job is have lemma_name := lemma_name, but informally it is the equivalent of recall theorem <lemma_name> in mathematical english. It could be accompanied by a recall? <insert the shape of the theorem> which then calls something like loogle and says try this : recall <matching lemma name>

Shreyas Srinivas (Jun 27 2024 at 15:14):

It could just be a macro for have : <statement> := by exact? plus some code to add hypotheses

Shreyas Srinivas (Jun 27 2024 at 15:15):

The goal is not to invent a new tactic, just provide ergonomic options that match math english.

Peter Nelson (Jun 28 2024 at 11:17):

I think this recall would be really nice! Doing have := theorem_name usually fails because of metavariables, and have := @theorem_name and have’ := theorem_name can both give unreadable output. This is worse in lean 4 that is was in lean 3.

It would be good to have a quick way to see something like what #check shows, but as a hypothesis.

Johan Commelin (Jun 28 2024 at 11:20):

observe is almost that tactic

Jon Eugster (Jun 28 2024 at 11:36):

It's only today that I realised you can write #check theorem_name inside a tactic proof too, and not only outside a statement as a command.

import Mathlib

example : 5 = 5 := by
  #check Real.pi_div_four_le_arcsin
  rfl

Shreyas Srinivas (Jun 28 2024 at 11:58):

From a stylistic POV, a proof that that reads.

recall <lemma_name>
apply <assumption 1> at <lemma name>
apply <assumption 2> at <lemma name>
...
...

Is immediately legible to someone who wishes to understand the high level flow of the proof even before they get into the infoview. Note that I am using my version of apply at here so the hypothesis name remains <lemma_name> after each apply at.

PS (CW: idle speculation): Going further with the whole "math English" style, rw feels more English like if it said rewrite <hypothesis> with [eq1, eq2,....]


Last updated: May 02 2025 at 03:31 UTC