Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: How to `have` an `Expr`?


Alexander Bentkamp (Dec 31 2025 at 14:16):

Hello, I would like to invoke have within metaprogramming like this:

import Lean

open Lean Meta Elab Tactic

elab "test" : tactic => do
    let expr : Expr := mkConst `Nat.zero_lt_one
    evalTactic $  `(tactic| have h := Nat.zero_lt_one) -- how to use `expr` here?

example : False := by
  test
  sorry

I don't have the expression I want to "have" as Syntax, but as an Expr. How can I make this work?

Ideally, I would also like to know the FVarId introduced by the have.

Henrik Böving (Dec 31 2025 at 14:19):

have is just a let binder that is non dependent. So you would call Lean.Meta.withLetDecl with nondep := true and then Lean.Meta.mkLetFVars to make the binder

Alexander Bentkamp (Dec 31 2025 at 14:32):

Hm, this works, but I didn't need to use Lean.Meta.mkLetFVars. Is this correct?

import Lean

open Lean Meta Elab Tactic

#check Lean.Meta.withLetDecl
#check Lean.Meta.mkLetFVars

elab "test" : tactic => do
    let mvar  getMainGoal
    let mvarType  inferType (mkMVar mvar)
    let expr : Expr := mkConst `Nat.zero_lt_one
    Lean.Meta.withLetDecl (nondep := true) `h ( inferType expr) expr fun fvar => do
      let newMVar  mkFreshExprMVar mvarType
      mvar.assign newMVar
      replaceMainGoal [newMVar.mvarId!]

example : False := by
  test
  sorry

Henrik Böving (Dec 31 2025 at 14:38):

Ah, to do specifically that thing no, but if you want to do a have followed by some other stuff in a general expression you would have to. For the specific use case of just injecting new hypotheses into a goal there is also Lean.MVarId.assertHypotheses

Alexander Bentkamp (Dec 31 2025 at 14:43):

Ah, great, that's what I was looking for. Thanks!


Last updated: Feb 28 2026 at 14:05 UTC