Zulip Chat Archive

Stream: lean4

Topic: Exclude variables when `subst_vars`


Clément Blaudeau (Sep 17 2025 at 08:49):

I'd like to do subst_vars but keeping some of the variables. Looking at the manual, it does not seems like it's a built-in option of subst_vars. Is there a workaround/trick ?

Typically, with the following example:

theorem foo a b c :
  a = 7189283767892987637829987 -- very long expression that I don't want to duplicate
   b = (a + a) * a + a -- intermediate variable that I want to substitute
   c = b * a + b * b * b
   c + 1 = 0
  := by
  intros
  subst b c -- works, but unsatisfactory
  sorry

I would like to subst b and c but without naming them (I have 30+ variables to subst, and their names are not exposed)
Is there some equivalent to subst_vars [-a] ?
Thank for your help!

Kim Morrison (Sep 18 2025 at 01:55):

Could you use revert/intro?

František Silváši 🦉 (Sep 18 2025 at 11:52):

I am not sure how resilient this version is (e.g. it doesn't bother with HEq) but it works for this example and can be extended for your use case :).

import Lean
import Qq

open Lean Qq

def substEqsSed (reject : Array Name) (mvarId : MVarId) : MetaM (Option MVarId) := do
  let mvarIds  mvarId.casesRec fun ldecl  do
    let type  instantiateMVarsQ (α := q(Prop)) ldecl.type
    let ~q($lhs = _) := type | return false
    let Expr.fvar name := lhs | return false
    return !reject.contains (name.getUserName)
  Meta.ensureAtMostOne mvarIds

elab "subst_but" reject:ident* : tactic =>
  Elab.Tactic.liftMetaTactic1  substEqsSed <| reject.map (·.getId)

theorem foo a b c :
  a = 7189283767892987637829987 -- very long expression that I don't want to duplicate
   b = (a + a) * a + a -- intermediate variable that I want to substitute
   c = b * a + b * b * b
   c + 1 = 0
  := by
  intros
  subst_but a -- same result as `subst b c`
  sorry

Clément Blaudeau (Sep 21 2025 at 17:26):

Thank you for the macro! I'll try it out on my non-minimized example and report how it went!


Last updated: Dec 20 2025 at 21:32 UTC