Zulip Chat Archive

Stream: lean4

Topic: Using new local declarations in the elaborator


Simon Hudon (Jul 27 2023 at 17:39):

I have the following code snippet:

def test : TermElabM Unit :=
let nat := mkConst ``Nat []
withLocalDeclD `x nat λ x => do
  let e  Term.elabTerm ( `(x + x)) nat
  println!"{← instantiateMVars e}"

#eval test

and I get this print out:

HAdd.hAdd.{0, 0, 0} Nat Nat Nat (instHAdd.{0} Nat instAddNat) (sorryAx.{1} Nat Bool.true) (sorryAx.{1} Nat Bool.true)
<CoreM>:0:0: error: unknown identifier 'x'

<CoreM>:0:0: error: unknown identifier 'x'

I was hoping that withLocalDeclD would make the new variable x available in the elaborator but it only elaborates it into sorryAx and then printing the resulting term gives two error messages (they disappear if I remove the println). How can I make x visible during elaboration?

Kyle Miller (Jul 27 2023 at 17:53):

@Simon Hudon Here's one way to make it be "visible", though it's by making sure to insert x as an expression:

open Lean Elab Tactic Meta in
def test : TermElabM Unit :=
  let nat := mkConst ``Nat []
  withLocalDeclD `x nat λ x => do
    let x'  Term.exprToSyntax x
    let e  Term.elabTerm ( `($x' + $x')) nat
    --Term.synthesizeSyntheticMVars -- < optional here
    dbg_trace "{← instantiateMVars e}"

Kyle Miller (Jul 27 2023 at 17:54):

If you're really going for name capture, then you can adjust the hygiene settings for the quasiquotation:

open Lean Elab Tactic Meta in
def test : TermElabM Unit :=
  let nat := mkConst ``Nat []
  withLocalDeclD `x nat λ _ => do
    let e  Term.elabTerm ( set_option hygiene false in `(x + x)) nat
    dbg_trace "{← instantiateMVars e}"

Gabriel Ebner (Jul 27 2023 at 17:58):

IMHO the preferred option is to just use the right x as the free variable name:

import Lean
open Lean Meta Elab

def test : TermElabM Unit := do
  let nat := .const ``Nat []
  withLocalDeclD ( `(x)).1.getId nat fun x => do
    let e  Term.elabTerm ( `(x + x)) nat
    logInfo ( instantiateMVars e)

#eval test

Gabriel Ebner (Jul 27 2023 at 18:02):

--Term.synthesizeSyntheticMVars -- < optional here

BTW, I've recently learned of withSynthesize which only synthesizes the mvars created in the block. (As opposed to synthesizeSyntheticMVars, which also tries to synthesize all synthetic mvars from other, previous elaborators.)

Simon Hudon (Jul 27 2023 at 18:04):

Thank you both! If I understand correctly, my problem came from the fact that I used `x as the name of my variable but when the elaborator encounters x in the syntax tree, it doesn't look up x but `x._@.Module._hyg.1 (for the given hygienic scope). Is this right?

Simon Hudon (Jul 27 2023 at 18:06):

BTW, I've recently learned of withSynthesize which only synthesizes the mvars created in the block. (As opposed to synthesizeSyntheticMVars, which also tries to synthesize all synthetic mvars from other, previous elaborators.)

Cool so it's like you separate two elaborators with a withNewMCtxDepth call, is that right?

Gabriel Ebner (Jul 27 2023 at 18:09):

A bit, yeah. The withSynthesize combinator resets the list of synthetic mvars at the beginning of the block and then appends them again when it's finished.

Simon Hudon (Jul 27 2023 at 18:16):

I think I still have a whole lot to learn about meta variable kinds and I wasn't aware that there was a list of synthetic variables. I assume meta variables get added to it when you call mkFreshExprMVar and otherwise, there's probably no reasons to add anything to it.

Gabriel Ebner (Jul 27 2023 at 18:22):

Oh, then you're completely confused. :smile: Synthetic metavariables and metavariables are completely different things. Synthetic metavariables are 1) type class constraints + 2) tactic blocks + 3) postponed term elaborators. Synthesizing the synthetic metavariables means running TC synthesis, running the tactic blocks, and trying the term elaborators again.

Kyle Miller (Jul 27 2023 at 18:22):

It gets added if you do docs#Lean.Elab.Term.registerSyntheticMVar

Simon Hudon (Jul 27 2023 at 18:33):

Aaah! Thanks!

Synthetic metavariables and metavariables are completely different things.

But they still use Expr.mvar nodes, I assume, don't they? How different is completely different?

Kyle Miller (Jul 27 2023 at 18:40):

My understanding is that a synthetic metavariable is three things together: the Expr.mvar node (and an entry in the metavariable table), an entry in the synthetic metavariables table, and its presence in the pending metavariables list.

Simon Hudon (Jul 27 2023 at 18:44):

That clears it up, thank you. I should bookmark this answer


Last updated: Dec 20 2023 at 11:08 UTC