Zulip Chat Archive

Stream: lean4

Topic: Propagation of intermediate instances in grind


Robin Carlier (Aug 06 2025 at 15:25):

Consider this very artificial mwe

class Even (n : Nat) : Prop where

class Odd (n : Nat) : Prop where

theorem even_and_odd (n : Nat) [Even n] [Odd n] : n = 0 := sorry

instance even_add (n m : Nat) [Even n] [Even m] : Even (n + m) := sorry

structure Foo (n : Nat) : Prop where

theorem foo_iff_even (n : Nat) : Foo n  Even n := sorry

theorem foo_and_odd_add (n m : Nat) (h : Foo n) [Even m] [Odd (n + m)] : n + m = 0 := by
  -- grind [even_add, even_and_odd, foo_iff_even]  -- fails but the following two works
  haveI := (foo_iff_even n).mp h
  grind [even_add, even_and_odd]

The failure on the commented line indicates that grind does assert Even n as a "true fact", but it fails to go further, complaining that it can’t infer an Even n instance to instantiate even_add, when the instance is registered beforehand, it’s okay. I guess this is because grind does not try to re-synth instances at each generation (that would be too expensive maybe?)

A "real world" example where this kind of things arise is category theory: you have some (non-instance) lemmas that tell you that a morphism is an epimorphism or monomorphism (e.g from a Function.injective hyp in concrete categories), that can’t be instance (because e.g Function.injective is not a class). Then, you have a bunch of lemmas that expects a Mono instance, and grind is unable to use them as soon as a goal starts from some Function.injective hyps.

For an example in mathlib that concretely prompted this question, in file#Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean, line 58, you can’t replace

        have h' := len_le_of_epi (SimplexCategory.epi_iff_surjective.2 h)
        dsimp at h'
        omega

by

        grind [ len_le_of_epi, len_mk, SimplexCategory.epi_iff_surjective]

but you can only replace it by

        have := epi_iff_surjective.2 h
        grind [ len_le_of_epi, len_mk]

and it would be nice if this could be a one-liner.

Is there a workaround around this? An option that tells grind to resynthesize instances between generations? or is that kind of things simply out of scope for this tactic?


Last updated: Dec 20 2025 at 21:32 UTC