Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: How to call a simp lemma within a simproc?


George Pîrlea (Dec 30 2024 at 09:01):

This doesn't work, and I'm not sure why. Any clue what I'm doing wrong?

import Lean
open Lean Meta Elab Tactic

def elim_exists_eq_impl : Simp.Simproc := fun e => do
  let thms := ( (simpOnlyBuiltins ++ [``exists_eq_left]).foldlM (·.addConst ·) ({} : SimpTheorems))
  let ctx : Simp.Context := {
    config := ( Simp.getContext).config
    simpTheorems := #[thms]
    congrTheorems := ( getSimpCongrTheorems)
  }
  let (res, _stats)  Simp.main e ctx
  trace[debug] "Result: {res.expr}"
  return .continue res

#check exists_eq_left

-- I'm not sure if this (pattern declaration) is needed
simproc_decl elim_exists_eq ( _, _) := elim_exists_eq_impl

set_option trace.debug true

theorem xx (s' : Nat):  s, s = s'  True := by
  -- simp only [exists_eq_left] -- this works
  simp only [elim_exists_eq] -- this doesn't; WHY?

To give some context of what I'm trying to accomplish:

I have a larger simproc to eliminate redundant existential quantifiers in goals by "pushing" the quantified variable to the right (such that it's the right-most quantifier) and then "pushing" the equality involving that quantifier to the left over conjunction in the quantified formula (such that's it's the left-most conjunct). After this transformation (and potentially using and_assoc), exists_eq_left should get rid of the quantifier. I'd want to call exists_eq_left within my larger simproc, but I don't know how.

George Pîrlea (Dec 30 2024 at 09:30):

"Manually" recreating the behaviour of exists_eq_left as a simproc works, but is quite unwieldly:

import Lean
open Lean Meta Elab Tactic

theorem exists_eq_left_thm :  {α : Sort u_1} {p : α  Prop} {a' : α}, ( a, a = a'  p a) = p a' :=
  propext exists_eq_left

def elim_exists_manual : Simp.Simproc := fun e => do
  let_expr Exists t eBody := e | return .continue
  -- the body of an `∃` is a lambda
  let step  lambdaBoundedTelescope eBody (maxFVars := 1) (fun ks lBody => do
      let #[k] := ks
        | throwError "Expected exactly one variable in the lambda telescope"
      let_expr And l r  lBody | return .continue
      let_expr Eq _ lhs rhs  l | return .continue
      if  isDefEq lhs k then
        let r'  mkLambdaFVars #[lhs] r
        let newBody  Core.betaReduce $ mkAppN r' #[rhs]
        let proof  mkAppOptM ``exists_eq_left_thm #[t, r', rhs]
        return .done { expr := newBody, proof? := proof }
      else
        return .continue
  )
  return step

simproc_decl elim_exists_eq ( _, _) := elim_exists_manual

theorem xx (s' : Nat):  s, s = s'  True := by
  simp only [elim_exists_eq] -- this works

Last updated: May 02 2025 at 03:31 UTC