Zulip Chat Archive

Stream: lean4

Topic: grind cannot see past CoeFun


Jakub Nowak (Sep 09 2025 at 06:26):

import Mathlib

namespace Sym2'

inductive Rel (α : Type u) : α × α  α × α  Prop
  | refl (x y : α) : Rel _ (x, y) (x, y)
  | swap (x y : α) : Rel _ (x, y) (y, x)

def Rel.setoid (α : Type u) : Setoid (α × α) :=
  Rel α, sorry

abbrev Sym2 (α : Type u) := Quotient (Rel.setoid α)

abbrev Sym2.mk {α : Type u} (p : α × α) : Sym2 α := Quotient.mk (Rel.setoid α) p

example {x y z w : α} : Sym2.mk (x, y) = Sym2.mk (z, w)  x = z  y = w  x = w  y = z := by
  -- This works.
  simp only [Quotient.eq, Rel.setoid]
  grind only [Rel]

example {x y z w : α} : Sym2.mk (x, y) = Sym2.mk (z, w)  x = z  y = w  x = w  y = z := by
  -- This works.
  simp only [Quotient.eq]
  show Rel α (x, y) (z, w)  x = z  y = w  x = w  y = z
  grind only [Rel]

example {x y z w : α} : Sym2.mk (x, y) = Sym2.mk (z, w)  x = z  y = w  x = w  y = z := by
  -- This doesn't work.
  grind [Quotient.eq, Rel.setoid, Rel]
  -- True propositions contain
  -- [prop] (Rel.setoid α) (x, y) (x, y)
  -- [prop] (Rel.setoid α) (x, y) (z, w)
  -- [prop] (Rel.setoid α) (z, w) (x, y)
  -- [prop] (Rel.setoid α) (z, w) (z, w)
  -- but no
  -- [prop] Rel α (x, y) (x, y)
  -- [prop] Rel α (x, y) (z, w)
  -- [prop] Rel α (z, w) (x, y)
  -- [prop] Rel α (z, w) (z, w)

end Sym2'

Although, it works in this smaller case I've tried to make:

structure Foo where
  f : Nat  Nat

instance : CoeFun Foo (fun _  Nat  Nat) where
  coe := Foo.f

variable (foo : Foo)

example : foo 2 = foo.f 2 := by
  simp only

example : foo 2 = foo.f 2 := by
  grind only

Not sure why that happens then.

Jakub Nowak (Sep 09 2025 at 06:38):

So, I think what's happening is that (Rel.setoid α) (x, y) (x, y) and Rel α (x, y) (x, y) are just defeq, but grind won't convert first to the second, because there are not grind_patterns that would lead it to this conversion.

Although I'm still not sure why adding Rel.setoid to simp patterns made it successfully convert (Rel.setoid α) (x, y) (x, y) to Rel α (x, y) (x, y), but grind wasn't able to do that conversion, even though there's Rel.setoid.eq_1: [Rel.setoid #0] pattern.

Jakub Nowak (Sep 09 2025 at 08:22):

I've tried adding

theorem t₁ {α : Type u} {s : Setoid α} {a b : α} : s a b  s.r a b := Iff.rfl
grind_pattern t₁ => s a b

but the E-matching pattern from this t₁: [@Setoid.r #3 #2 #1 #0], which is kinda weird, why is it t₁: [@Setoid.r #3 #2 #1 #0], and not t₁: [@Setoid #3 #2 #1 #0]? I think this might be the main cause of the problem.

Jakub Nowak (Sep 09 2025 at 08:30):

Adding this works though.

@[grind?]
theorem t₂ {α : Type u} {a b : α × α} : Rel.setoid α a b  Rel α a b := Iff.rfl

Jakub Nowak (Sep 09 2025 at 08:54):

I think I finally understand the issue. grind displays (Rel.setoid α) (x, y) (x, y) and doesn't display (Rel.setoid α).r (x, y) (x, y) because they are exactly the same. The first is delaborated version of the second.

Now, adding

@[grind?]
theorem t₃ {α : Type u} {a b : α × α} : (Rel.setoid α).r a b  Rel α a b := Iff.rfl

makes grind [Quotient.eq, Rel] work.

So it seems like the real issue is that grind cannot unfold projection.

Jakub Nowak (Sep 09 2025 at 11:22):

I made another topic: #lean4 > `grind` should unfold projections.


Last updated: Dec 20 2025 at 21:32 UTC