Skip to content

Commit 0ae200a

Browse files
committed
feat: grind_pattern where clauses, and #grind_lint
1 parent d87e74d commit 0ae200a

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

Manual/Grind/EMatching.lean

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ grind_pattern $_ => $_,*
8787
```
8888
Associates a theorem with one or more patterns.
8989
When multiple patterns are provided in a single {keywordOf Lean.Parser.Command.grind_pattern}`grind_pattern` command, _all_ of them must match a term before {tactic}`grind` will attempt to instantiate the theorem.
90+
91+
```grammar
92+
grind_pattern $_ => $_,* where $_
93+
```
94+
The optional {keywordOf Lean.Parser.Command.grind_pattern}`where` clause specifies constraints that must be satisfied before {tactic}`grind` attempts to instantiate the theorem.
95+
Each constraint has the form `variable =/= value`, preventing instantiation when the pattern variable would be assigned the specified value.
96+
This is useful to avoid unbounded or excessive instantiations with problematic terms.
9097
:::
9198

9299
::::example "Selecting Patterns"
@@ -183,6 +190,39 @@ The multi-pattern `R x y, R y z` instructs {tactic}`grind` to instantiate {lean}
183190
In the example, {tactic}`grind` applies {lean}`Rtrans` to derive {lean}`R a c` from {lean}`R a b` and {lean}`R b c`, and can then repeat the same reasoning to deduce {lean}`R a d` from {lean}`R a c` and {lean}`R c d`.
184191
::::
185192

193+
::::example "Pattern Constraints"
194+
Certain combinations of theorems can lead to unbounded instantiation, where E-matching repeatedly generates longer and longer terms.
195+
Consider theorems about {name}`List.flatMap` and {name}`List.reverse`.
196+
If {name}`List.flatMap_def`, {name}`List.flatMap_reverse`, and {name}`List.reverse_flatMap` are all annotated with {attrs}`@[grind =]`, then as soon as {name}`List.flatMap_reverse` is instantiated, the following chain of instantiations occurs, creating progressively longer function compositions with {name}`List.reverse`.
197+
This can be observed using the `#grind_lint` command:
198+
```
199+
attribute [local grind =] List.reverse_flatMap
200+
201+
set_option trace.grind.ematch.instance true in
202+
#grind_lint inspect List.flatMap_reverse
203+
```
204+
The trace output shows the unbounded instantiation:
205+
```
206+
[grind.ematch.instance] List.flatMap_def: List.flatMap (List.reverse ∘ f) l = (List.map (List.reverse ∘ f) l).flatten
207+
[grind.ematch.instance] List.flatMap_def: List.flatMap f l.reverse = (List.map f l.reverse).flatten
208+
[grind.ematch.instance] List.flatMap_reverse: List.flatMap f l.reverse = (List.flatMap (List.reverse ∘ f) l).reverse
209+
[grind.ematch.instance] List.reverse_flatMap: (List.flatMap (List.reverse ∘ f) l).reverse =
210+
List.flatMap (List.reverse ∘ List.reverse ∘ f) l.reverse
211+
[grind.ematch.instance] List.flatMap_def: List.flatMap (List.reverse ∘ List.reverse ∘ f) l.reverse =
212+
(List.map (List.reverse ∘ List.reverse ∘ f) l.reverse).flatten
213+
```
214+
215+
This pattern continues indefinitely, with each iteration adding another {lean}`List.reverse` to the composition.
216+
The {keywordOf Lean.Parser.Command.grind_pattern}`where` clause prevents this by excluding problematic instantiations:
217+
```
218+
grind_pattern reverse_flatMap => (l.flatMap f).reverse where
219+
f =/= List.reverse ∘ _
220+
```
221+
This instructs {tactic}`grind` to use the pattern `(l.flatMap f).reverse`, but only when `f` is not a composition with {name}`List.reverse`, preventing the unbounded chain of instantiations.
222+
223+
You can use `#grind_lint check` to look for problematic patterns, or `#grind_lint check in List` or `#grind_lint check in module Std.Data` to look in specific namespaces or modules.
224+
::::
225+
186226
The {attr}`grind` attribute automatically generates an E-matching pattern or multi-pattern using a heuristic, instead of using {keywordOf Lean.Parser.Command.grindPattern}`grind_pattern` to explicitly specify a pattern.
187227
It includes a number of variants that select different heuristics.
188228
The {attr}`grind?` attribute displays an info message showing the pattern which was selected—this is very helpful for debugging!

lean-toolchain

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
leanprover/lean4:v4.25.0
1+
leanprover/lean4:nightly-2025-11-16

0 commit comments

Comments
 (0)