Zulip Chat Archive
Stream: mathlib4
Topic: Proofs with HEq goals
Julia Scheaffer (Sep 04 2025 at 22:20):
Recently, I have learned how to use cast, and that is going great, but occasionally I get goals that use HEq which I don't know how to solve. Usually I can change these to use cast and solve them, but not always. Here is a recent example i have attempted to minimize.
import Mathlib
inductive Stack.{u} : List (Type u) -> Type (u + 1) where
| nil : Stack []
| cons {α β}: α -> Stack β -> Stack (α :: β)
infixr:67 "; " => Stack.cons
variable {A : Type u} {α β : List (Type u)} {a : Stack α} {b : Stack β}
def Stack.cast (a : Stack α) (h : α = β) : Stack β := h ▸ a
theorem Stack.eq_cast_iff_heq (h : α = β) : a = b.cast h.symm <-> a ≍ b := by
rw [Stack.cast, Eq.rec_eq_cast, _root_.eq_cast_iff_heq]
theorem Stack.cons_cancel {x : A} {h : α = β} :
x; a = (x; b).cast (by rw [h]) -> a = b.cast h.symm := by
rw [eq_cast_iff_heq (by rw [h]), eq_cast_iff_heq h]
-- I dont know how to use function injectivity over heq
grind only [cons.inj]
-- But thankfully grind does!
In this case I needed to use the injectivity of cons to reach my goal, but I don't know how to do this across an HEq instead of a normal equality. Thankfully grind does know how, but I would like to rewrite this without using grind. What sort of tactics is grind using in this situation?
I have also come across other situations where I can't solve a goal, but grind does in some non-obvious (to me) way.
Aaron Liu (Sep 04 2025 at 22:24):
theorem Stack.cons_cancel {x : A} {h : α = β} :
x; a = (x; b).cast (by rw [h]) -> a = b.cast h.symm := by
rw [eq_cast_iff_heq (by rw [h]), eq_cast_iff_heq h]
subst h
rw [heq_iff_eq, heq_iff_eq]
intro h
exact (cons.inj h).2
Julia Scheaffer (Sep 04 2025 at 22:31):
I didn't know about the subst tactic. Thank you!
Kyle Miller (Sep 09 2025 at 14:30):
Most cast lemmas can start with subst_vars, and then you can treat the cast as being an id.
theorem Stack.eq_cast_iff_heq (h : α = β) : a = b.cast h.symm <-> a ≍ b := by
subst_vars
rw [heq_iff_eq]
rfl
theorem Stack.cons_cancel {x : A} {h : α = β} :
x; a = (x; b).cast (by rw [h]) -> a = b.cast h.symm := by
subst_vars
intro h
exact (cons.inj h).2
Kyle Miller (Sep 09 2025 at 14:32):
For your lemmas, it's good to make sure the hypotheses are used as pure variables, for example avoiding use of h.symm and instead phrase it as
theorem Stack.eq_cast_iff_heq (h : β = α) : a = b.cast h <-> a ≍ b := by
subst_vars
rw [heq_iff_eq]
rfl
That way when you rewrite with the lemma, Lean can solve for h by unification, and you don't need to supply it as an argument to the lemma.
Julia Scheaffer (Sep 09 2025 at 15:56):
Kyle Miller said:
For your lemmas, it's good to make sure the hypotheses are used as pure variables, for example avoiding use of
h.symmand instead phrase it as ...
Thank you for the recommendation! This has shortened a couple of my proofs by a few lines :smile:
Last updated: Dec 20 2025 at 21:32 UTC