feat: `guard` and `check` in `grind_pattern` (#11428) This PR implements support for **guards** in `grind_pattern`. The new feature provides additional control over theorem instantiation. For example, consider the following monotonicity theorem: ```lean opaque f : Nat → Nat theorem fMono : x ≤ y → f x ≤ f y := ... ``` We can use `grind_pattern` to instruct `grind` to instantiate the theorem for every pair `f x` and `f y` occurring in the goal: ```lean grind_pattern fMono => f x, f y ``` Then we can automatically prove the following simple example using `grind`: ```lean /-- trace: [grind.ematch.instance] fMono: f a ≤ b → f (f a) ≤ f b [grind.ematch.instance] fMono: f a ≤ c → f (f a) ≤ f c [grind.ematch.instance] fMono: f a ≤ a → f (f a) ≤ f a [grind.ematch.instance] fMono: f a ≤ f (f a) → f (f a) ≤ f (f (f a)) [grind.ematch.instance] fMono: f a ≤ f a → f (f a) ≤ f (f a) [grind.ematch.instance] fMono: f (f a) ≤ b → f (f (f a)) ≤ f b [grind.ematch.instance] fMono: f (f a) ≤ c → f (f (f a)) ≤ f c [grind.ematch.instance] fMono: f (f a) ≤ a → f (f (f a)) ≤ f a [grind.ematch.instance] fMono: f (f a) ≤ f (f a) → f (f (f a)) ≤ f (f (f a)) [grind.ematch.instance] fMono: f (f a) ≤ f a → f (f (f a)) ≤ f (f a) [grind.ematch.instance] fMono: a ≤ b → f a ≤ f b [grind.ematch.instance] fMono: a ≤ c → f a ≤ f c [grind.ematch.instance] fMono: a ≤ a → f a ≤ f a [grind.ematch.instance] fMono: a ≤ f (f a) → f a ≤ f (f (f a)) [grind.ematch.instance] fMono: a ≤ f a → f a ≤ f (f a) [grind.ematch.instance] fMono: c ≤ b → f c ≤ f b [grind.ematch.instance] fMono: c ≤ c → f c ≤ f c [grind.ematch.instance] fMono: c ≤ a → f c ≤ f a [grind.ematch.instance] fMono: c ≤ f (f a) → f c ≤ f (f (f a)) [grind.ematch.instance] fMono: c ≤ f a → f c ≤ f (f a) [grind.ematch.instance] fMono: b ≤ b → f b ≤ f b [grind.ematch.instance] fMono: b ≤ c → f b ≤ f c [grind.ematch.instance] fMono: b ≤ a → f b ≤ f a [grind.ematch.instance] fMono: b ≤ f (f a) → f b ≤ f (f (f a)) [grind.ematch.instance] fMono: b ≤ f a → f b ≤ f (f a) -/ #guard_msgs in example : f b = f c → a ≤ f a → f (f a) ≤ f (f (f a)) := by set_option trace.grind.ematch.instance true in grind ``` However, many unnecessary theorem instantiations are generated. With the new `guard` feature, we can instruct `grind` to instantiate the theorem **only if** `x ≤ y` is already known to be true in the current `grind` state: ```lean grind_pattern fMono => f x, f y where guard x ≤ y x =/= y ``` If we run the example again, only three instances are generated: ```lean /-- trace: [grind.ematch.instance] fMono: a ≤ f a → f a ≤ f (f a) [grind.ematch.instance] fMono: f a ≤ f (f a) → f (f a) ≤ f (f (f a)) [grind.ematch.instance] fMono: a ≤ f (f a) → f a ≤ f (f (f a)) -/ #guard_msgs in example : f b = f c → a ≤ f a → f (f a) ≤ f (f (f a)) := by set_option trace.grind.ematch.instance true in grind ``` Note that `guard` does **not** check whether the expression is *implied*. It only checks whether the expression is *already known* to be true in the current `grind` state. If this fact is eventually learned, the theorem will be instantiated. If you want `grind` to check whether the expression is implied, you should use: ```lean grind_pattern fMono => f x, f y where check x ≤ y x =/= y ``` Remark: we can use multiple `guard`/`check`s in a `grind_pattern` command.
This is the repository for Lean 4.
See Install Lean.
Please read our Contribution Guidelines first.
See Building Lean.