Zulip Chat Archive
Stream: lean4
Topic: Produce proof expression containing let_fun
Bhavik Mehta (Apr 30 2025 at 13:57):
I'm trying to produce a proof term, where there's a certain amount of shared subexpressions in the final proof. So, I'd like to use let_fun
(or similar) to produce let_fun x := long_proof; h x x
instead of h long_proof long_proof
. I found docs#Lean.Meta.mkLetFun, which seems like exactly what I want, but I don't understand how to manage the fvars to make this happen. As an example, I'm first trying to make a tactic which produces let_fun x := sorry; x
, but I get panic because of unknown free variables. What am I doing wrong?
import Lean
open Lean Elab Meta Tactic
elab "test" : tactic => liftMetaFinishingTactic fun goal ↦ do
let t ← goal.getType
let i := FVarId.mk `h1
let p ← mkLetFun (.fvar i) (← mkSorry t false) (.fvar i)
goal.assign p
example : 2 = 3 := by test
Bhavik Mehta (Apr 30 2025 at 13:59):
For concreteness, here's the proof term I want the test
tactic to create here:
example : 2 = 3 := let_fun h1 := (sorry : 2 = 3); h1
Aaron Liu (Apr 30 2025 at 14:01):
This is what I would do
elab "test" : tactic => liftMetaFinishingTactic fun goal ↦ do
let t ← goal.getType
let i ← mkFreshExprMVar (some t)
let p ← mkLetFun i (← mkSorry t false) i
goal.assign p
Bhavik Mehta (Apr 30 2025 at 14:03):
Oh, with a new mvar instead of a new fvar, interesting
Robin Arnez (Apr 30 2025 at 14:04):
If you want an fvar:
elab "test" : tactic => liftMetaFinishingTactic fun goal ↦ do
let t ← goal.getType
let value ← mkSorry t false
let p ← withLocalDecl `h1 .default t fun fvar => do
let expr := fvar
mkLetFun fvar value expr
goal.assign p
You can't just use FVarId.mk
to make a new fvar because then it won't be in the local context. Instead, use something like withLocalDecl
Aaron Liu (Apr 30 2025 at 14:06):
I couldn't find the function withLocalDecl
, which is why I used an mvar
Bhavik Mehta (Apr 30 2025 at 14:06):
I don't particularly mind whether it's an mvar or an fvar; I just presumed fvar was the thing to use here! Does it make a difference which one I use?
Robin Arnez said:
it won't be in the local context
Interesting: since this is meant to be a finishing tactic I imagined that it doesn't matter whether it's in the local context, since the new binding wouldn't be user-facing... Thanks for the fix!
Robin Arnez (Apr 30 2025 at 14:07):
Well it uses it in particular for the type so it does need to exist in the local context
Aaron Liu (Apr 30 2025 at 14:08):
Bhavik Mehta said:
Interesting: since this is meant to be a finishing tactic I imagined that it doesn't matter whether it's in the local context, since the new binding wouldn't be user-facing... Thanks for the fix!
mkLetFun
needs it to be in the local context to work, that's where the error was coming from.
Bhavik Mehta (Apr 30 2025 at 14:09):
Aaron Liu said:
mkLetFun
needs it to be in the local context to work, that's where the error was coming from.
Makes sense, but does that mean mkLetFun
was the wrong thing to use?
Aaron Liu (Apr 30 2025 at 14:09):
You can also use Qq to construct the expression without any MetaM
Bhavik Mehta (Apr 30 2025 at 14:45):
I ended up using the mvar solution and it works nicely, thanks!
Last updated: May 02 2025 at 03:31 UTC