Zulip Chat Archive

Stream: general

Topic: Grind manual arguments patterns


Moritz R (Jan 08 2026 at 17:18):

I have had the situation that a proof using grind [mylemma] succeeded, but tagging the lemma with @[grind] (and calling grind) didn't.
So I am wondering which patterns are chosen for manual arguments to grind and if they can be viewed.

Moritz R (Jan 08 2026 at 17:20):

I didn't find this info in the docs, maybe it can be added if i really didn't just miss it

Kim Morrison (Jan 09 2026 at 05:42):

Usually this should work as you expected, so I would be interested in seeing a #mwe if it's possible to construct one.

In this case, usually set_option trace.grind.ematch.pattern true is helpful, as it will tell you which pattern was selected.

Kim Morrison (Jan 09 2026 at 05:49):

There's still a small manual step to write a grind_pattern command to reproduces a pattern you see from that trace option.

Are you using an old version of Lean, btw? If you tag a lemma with plain @[grind] you should always get a message about the different sigils you could use to select a particular pattern. (At least for theorems, for definitions @[grind] is expected.)

Moritz R (Jan 09 2026 at 12:22):

import Mathlib.Tactic

inductive Tree23 (α : Type u)
| nil
| node2 (l : Tree23 α) (a : α) (r : Tree23 α)
| node3 (l : Tree23 α) (a : α) (m : Tree23 α) (b : α) (r : Tree23 α)

namespace Tree23

universe u
variable {α : Type u}

def height : Tree23 α   
| nil => 0
| node2 l _ r => max (height l) (height r) + 1
| node3 l _ m _ r => max (height l) (max (height m) (height r)) + 1

lemma heightNil : height (nil : Tree23 α) = 0 := by simp [height]

def complete : Tree23 α   Bool
| nil => true
| node2 l _ r => height l = height r  complete l  complete r
| node3 l _ m _ r =>
  height l = height m  height m = height r  complete l  complete m  complete r

@[grind]
lemma not_nil_height_pos (t : Tree23 α) : t  nil  height t > 0 :=
  by induction t <;> simp [height]

set_option trace.grind.ematch.pattern true
/- Can't remove `not_nil_height_pos` from the grind call, altough it is annotated with `grind`.
   Annotating with `grind .` also doesn't work. Annotating with `grind! .` does work.
   How does grind decide what patterns are used in a manual call? -/
lemma failhere {l r : Tree23 α} (h : (l.node2 a r).complete = true) (hl : ¬l = nil) :
  r  nil := by grind [complete, heightNil, not_nil_height_pos]

end Tree23

Here is a smaller example of what i saw.

Moritz R (Jan 09 2026 at 12:25):

It looks to me, as if in a manual grind call, it just adds the generated patterns for all modifiers?
If this is true, i just want it to be added to the grind docs and then this is expected behavior

Moritz R (Jan 09 2026 at 12:28):

until now i would have thought, that probably grind [lemma] does the same as @[grind] or as @[grind .]

Kim Morrison (Jan 09 2026 at 20:36):

As you see, that's incorrect.

I think you must be using an old version, as I asked above?

On

@[grind]
lemma not_nil_height_pos (t : Tree23 α) : t  nil  height t > 0 :=
  by induction t <;> simp [height]

I see the message

Try these:
  [apply] [grind .] for pattern: [@LE.le `[] `[instLENat] `[1] (@height #2 #1)]
  [apply] [grind =>] for pattern: [@nil #2, @LE.le `[] `[instLENat] `[1] (@height _ #1)]
  [apply] [grind! .] for pattern: [@height #2 #1]
  [apply] [grind! =>] for pattern: [@nil #2, @height _ #1]

which is asking you to choose which pattern you want.

As an argument to grind, it picks the "more aggressive" grind! . pattern.

Moritz R (Jan 09 2026 at 20:47):

I used Lean 4 Web, on the most recent version availible

Moritz R (Jan 09 2026 at 20:48):

image.png
This is the message from the set_option trace.grind.ematch.pattern true and it prints exactly the same as the Try these suggestions (with duplicates)

Moritz R (Jan 09 2026 at 20:49):

How should i have seen this as incorrect? I thought maybe the duplicates belong to additional modifiers that aren't shown in the Try these, since they would be duplicated else

Moritz R (Jan 09 2026 at 20:52):

Kim Morrison schrieb:

As an argument to grind, it picks the "more aggressive" grind! . pattern.

That's the answer i was looking for. Thank you :) Can you also put this into the docs, please?

Moritz R (Jan 09 2026 at 20:57):

i listed "@[grind] does nothing" out of confusion, since e.g. that also does something, but yes it shouldn't here

Moritz R (Jan 09 2026 at 21:03):

Moritz R schrieb:

image.png
This is the message from the set_option trace.grind.ematch.pattern true and it prints exactly the same as the Try these suggestions (with duplicates)

What does this output tell me? Because there are 4 different patterns listed, but you say it should only use 1.

Moritz R (Jan 09 2026 at 21:04):

Sorry if im being a bit dense rn

Kim Morrison (Jan 10 2026 at 02:35):

Do you see the message on the @[grind] annotation? It is telling you that you should replace @[grind] with one of the four options it suggests, by clicking on one of the "Try this:" suggestions.

Moritz R (Jan 10 2026 at 10:05):

Yes, that one i understand. The other message which stems from the (traced) grind call with the manual arguments (see my screenshot above) is unclear to me. Why is there 6 patterns (4 when deduplicated) printed from that call?


Last updated: Feb 28 2026 at 14:05 UTC