Zulip Chat Archive

Stream: Is there code for X?

Topic: Subst with an expression


Snir Broshi (Feb 06 2026 at 07:40):

In foo I would like to rw [h] but "motive is not type correct" (using rw! does work, but Mathlib seems hesitant to adopt it, so I prefer not to use it).
Instead I can use foo_helper where the hypothesis is an equality of variables, so I can subst.
Is there a way to solve this directly in foo, perhaps using some generalize magic?

import Mathlib

variable {α β : Type*} {P : α  β  Prop} {Q : (a : α)  Sym2 { b : β // P a b }  Prop}

lemma foo_helper {a₁ a₂ : α} {b₁ b₂ : β} (h : a₁ = a₂) {h₁ h₂ h₃ h₄ h₅ h₆} :
    let T := Σ a : α, Subtype (Q a)
    (a₁, s(b₁, h₁, b₂, h₂), h₃ : T) = a₂, s(b₁, h₄, b₂, h₅), h₆ := by
  subst h
  rfl

lemma foo {f : β  α} {b₁ b₂ : β} (h : f b₁ = f b₂) {h₁ h₂ h₃ h₄ h₅ h₆} :
    let T := Σ a : α, Subtype (Q a)
    (f b₁, s(b₁, h₁, b₂, h₂), h₃ : T) = f b₂, s(b₁, h₄, b₂, h₅), h₆ := by
  exact foo_helper h

Snir Broshi (Feb 06 2026 at 07:42):

This becomes harder if I need another rewrite afterwards to finish, e.g. here's foo but with the pair on the RHS swapped so I need Sym2.eq_swap:

import Mathlib

variable {α β : Type*} {P : α  β  Prop} {Q : (a : α)  Sym2 { b : β // P a b }  Prop}

lemma foo2 {f : β  α} {b₁ b₂ : β} (h : f b₁ = f b₂) {h₁ h₂ h₃ h₄ h₅ h₆} :
    let T := Σ a : α, Subtype (Q a)
    (f b₁, s(b₁, h₁, b₂, h₂), h₃ : T) = f b₂, s(b₂, h₅, b₁, h₄), h₆ := by
  rw! [h, Sym2.eq_swap]
  rfl

Jakub Nowak (Feb 06 2026 at 09:19):

Snir Broshi said:

using rw! does work, but Mathlib seems hesitant to adopt it

Why is that? I use it often, it makes things easier. I've grepped rw! and it looks like it's already being used a few times in some proofs in mathlib.

Snir Broshi (Feb 06 2026 at 10:17):

idk, it's currently used in exactly 4 proofs across 3 files in Mathlib.
I think Mathlib.Tactic.Common has to import it for it to gain more usage

Jakub Nowak (Feb 06 2026 at 10:20):

Hm, I've tried writing these without rw! and was kinda surprised that conv did a dependant rewrite (of h₃).

import Mathlib

variable {α β : Type*} {P : α  β  Prop} {Q : (a : α)  Sym2 { b : β // P a b }  Prop}

lemma foo2 {f : β  α} {b₁ b₂ : β} (h : f b₁ = f b₂) {h₁ h₂ h₃ h₄ h₅ h₆} :
    (f b₁, s(b₁, h₁, b₂, h₂), h₃ : Σ a : α, Subtype (Q a)) = f b₂, s(b₂, h₅, b₁, h₄), h₆ := by
  -- same effect as `rw! [h]; clear h`
  generalize ha : f b₁ = a₁ at *
  generalize f b₂ = a₂ at *
  subst h ha

  -- same effect as `rw! [Sym2.eq_swap]; rfl`
  conv_lhs =>
    enter [2, 1]
    exact Sym2.eq_swap

Snir Broshi (Feb 06 2026 at 10:28):

Woah, amazing, thanks! So the at * is the solution to result is not type correct. Hmm, generalize confuses me

Jakub Nowak (Feb 06 2026 at 10:31):

Yes, generalize .. at * has more or less the same effect as defining the helper function. Without at * generalize will only rewrite the goal, which makes the goal not type correct, because you also need to do dependant rewrite of h₁, h₂, h₃, h₄, h₅, and h₆.

Jakub Nowak (Feb 06 2026 at 10:34):

E.g. in the expression ⟨f b₁, ⟨s(⟨b₁, h₁⟩, ⟨b₂, h₂⟩), h₃⟩⟩ the type of h₁ is P (f b₁) b₁, but in ⟨a₁, ⟨s(⟨b₁, h₁'⟩, ⟨b₂, h₂'⟩), h₃'⟩⟩ the type of h₁' needs to be P a₁ b₁, so you can't use h₁ directly.

Violeta Hernández (Feb 06 2026 at 22:09):

These are exactly the sorts of problems rw! is designed to solve, and I'd recommend you make use of it.

Snir Broshi (Feb 11 2026 at 22:23):

Relevant update: #13686 was just merged, and it adds import Mathlib.Tactic.DepRewrite to Mathlib.Tactic.Common :tada:
So I think I'll have no qualms using rw! moving forward

Violeta Hernández (Feb 27 2026 at 11:50):

(deleted)


Last updated: Feb 28 2026 at 14:05 UTC