Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: Confused by Metavariable occurance


William Sørensen (Jul 31 2024 at 15:02):

I was trying to see what certain expressions elab to so i wrote this little piece of code

open Parser.Term
elab "#test" t:term : command =>
  runTermElabM fun _ => do
    let x  Elab.Term.elabTerm t none
    let xType  inferType x
    let xChecked  Elab.Term.ensureHasType xType x
    let xFinal  instantiateMVars xChecked
    dbg_trace ( ppExpr xFinal)
    dbg_trace (repr xFinal)

#test (match Nat.zero with | _ => Nat.zero)
#test let rec x := 0; x

but it yielded some very suprising results:

?m.17667
Lean.Expr.mvar (Lean.Name.mkNum `_uniq 17667)

On the line with the match.

(fun x => x) ?m.17669
Lean.Expr.app
  (Lean.Expr.lam
    `x
    (Lean.Expr.mvar (Lean.Name.mkNum `_uniq 17673))
    (Lean.Expr.mdata
      { entries := [(`_recApp,
                     Lean.DataValue.ofSyntax
                       (Lean.Syntax.ident
                         (Lean.SourceInfo.original
                           "".toSubstring
                           { byteIdx := 6701 }
                           "\n".toSubstring
                           { byteIdx := 6702 })
                         "x".toSubstring
                         `x
                         []))] }
      (Lean.Expr.bvar 0))
    (Lean.BinderInfo.default))
  (Lean.Expr.mvar (Lean.Name.mkNum `_uniq 17669))

On the line with the let rec

So now my question is as follows, why are these mvars appearing here? I would expect these to elab into complete exprs, why do they not?

William Sørensen (Jul 31 2024 at 15:58):

Fixed a small error, was using the wrong elab, but results are still confusing

Jannis Limperg (Jul 31 2024 at 16:33):

It seems like the elaborator decided to postpone some tasks; the metavariables stand in for the postponed parts of the term. If you disable postponing, you at least get an informative error for the match. (Same behaviour as before for the let rec, but that one also confuses me in general.)

import Lean

open Lean Lean.Meta Lean.Elab.Command Lean.Elab.Term

elab "#test" t:term : command =>
  liftTermElabM do
    withoutPostponing do
    withSynthesize do
    withoutErrToSorry do
    let x  Elab.Term.elabTerm t none
    let xType  inferType x
    let xChecked  Elab.Term.ensureHasType xType x
    let xFinal  instantiateMVars xChecked
    dbg_trace ( ppExpr xFinal)
    dbg_trace (repr xFinal)

#test (match Nat.zero with | _ => Nat.zero)
#test let rec x := 0; x

The withSynthesize and withoutErrToSorry don't affect this example, but are needed in general if you want to elaborate something without allowing any funny business.

(Btw #mwe in future please, you were missing an import and some opens.)

William Sørensen (Aug 01 2024 at 11:42):

Ok nice thanks for the help, maybe Ill find some hack to avoid the let rec then...

William Sørensen (Aug 12 2024 at 10:20):

For closure on this, it looks like let recs are lifted up out of the expression and elab'd kinda like a def so i think this explains why the let rec did not elab, it needed a place to be lifted. idk this is kinda off vibes but noteworthy anyway


Last updated: May 02 2025 at 03:31 UTC