Zulip Chat Archive
Stream: lean4
Topic: Elaborator and @
Leni Aniva (Apr 15 2024 at 19:01):
Suppose we have
let e ← match Parser.runParserCategory
(env := <- MonadEnv.getEnv)
(catName := `term)
(input := "Nat.brecOn")
(fileName := "<stdin>") with
| .ok syn => pure syn
| .error error => throwError error
let e <- Elab.elabTerm e .none
The inferred type of e
is a metavariable, but if I replace Nat.brecOn
with @Nat.brecOn
, the inferred type becomes the full type of Nat.brecOn
. How can I enforce this effect during elaboration? I remember in one of the tactics this @
effect is enforced, but I forgot which one
Leni Aniva (Apr 16 2024 at 03:32):
According to the documentation:
/--
Main function for elaborating terms.
It extracts the elaboration methods from the environment using the node kind.
Recall that the environment has a mapping from `SyntaxNodeKind` to `TermElab` methods.
It creates a fresh macro scope for executing the elaboration method.
All unlogged trace messages produced by the elaboration method are logged using
the position information at `stx`. If the elaboration method throws an `Exception.error` and `errToSorry == true`,
the error is logged and a synthetic sorry expression is returned.
If the elaboration throws `Exception.postpone` and `catchExPostpone == true`,
a new synthetic metavariable of kind `SyntheticMVarKind.postponed` is created, registered,
and returned.
The option `catchExPostpone == false` is used to implement `resumeElabTerm`
to prevent the creation of another synthetic metavariable when resuming the elaboration.
If `implicitLambda == false`, then disable implicit lambdas feature for the given syntax, but not for its subterms.
We use this flag to implement, for example, the `@` modifier. If `Context.implicitLambda == false`, then this parameter has no effect.
-/
def elabTerm (stx : Syntax) (expectedType? : Option Expr) (catchExPostpone := true) (implicitLambda := true) : TermElabM Expr :=
withRef stx <| elabTermAux expectedType? catchExPostpone implicitLambda stx
I tried to pass in implicitLambda := true/false
but the result is the same. The elaboration generates a metavariable when there is no @
.
Kyle Miller (Apr 16 2024 at 03:41):
implicitLambda
is for @fun ...
vs fun ...
Do you know about Elab.elabAppArgs
?
Leni Aniva (Apr 16 2024 at 03:41):
Kyle Miller said:
implicitLambda
is for@fun ...
vsfun ...
Do you know about
Elab.elabAppArgs
?
yes, but I don't know how to use it in this case
Leni Aniva (Apr 16 2024 at 03:54):
If I run the elaboration monad in withoutHeedElabAsElim
/--
Execute `x` without heeding the `elab_as_elim` attribute. Useful when there is
no expected type (so `elabAppArgs` would fail), but expect that the user wants
to use such constants.
-/
def withoutHeedElabAsElim [MonadFunctorT TermElabM m] : m α → m α :=
monadMap (m := TermElabM) withoutHeedElabAsElimImp
The type of the elaborated symbol becomes
(t : Nat) → ((t : Nat) → Nat.below t → ?m.67 t) → ?m.67 t
which is almost correct except for that the motive argument is missing. The documentation of this function says without expected type (which is my use caes),elabAppArgs
would fail, but I still can't replicate the behaviour of @Nat.brecOn
Leni Aniva (Apr 16 2024 at 16:40):
Kyle Miller said:
implicitLambda
is for@fun ...
vsfun ...
Do you know about
Elab.elabAppArgs
?
I don't think I can use this function since I in this use case I don't have the arguments to Nat.brecOn
when I'm calling it. I just want to determine the type of this expression in context
Leni Aniva (Apr 16 2024 at 22:01):
This is a MWE. I read in Elab/Term.lean
that the automatic insertion of metavariables is related to autoBoundImplicit
but disabling it in the elaboration context did not do anything:
import Lean
open Lean
def parseTerm (s: String): CoreM Syntax := do
match Parser.runParserCategory
(env := ← MonadEnv.getEnv)
(catName := `term)
(input := s)
(fileName := "<stdin>") with
| .ok s => return s
| .error e => throwError e
def termElabM : Elab.TermElabM Unit := do
let expr := "Nat.brecOn"
let expr ← Elab.Term.elabTerm (← parseTerm expr) (expectedType? := .none)
let type ← Meta.inferType expr
IO.println s!"{← Meta.ppExpr expr}"
IO.println s!" : {← Meta.ppExpr type}"
let unassigned ← Elab.Term.collectUnassignedMVars type
for mvarId in unassigned do
let mvarType ← Meta.inferType mvarId
IO.println s!"{← Meta.ppExpr mvarId}: {← Meta.ppExpr mvarType}"
def main : IO Unit := do
let options: Options := {}
let options := options.setNat `pp.deepTerms.threshold 100
let options := options.setNat `pp.proofs.threshold 100
let env: Environment ← importModules
(imports := #[`Init])
(opts := {})
(trustLevel := 1)
let termElabContext: Elab.Term.Context := {
heedElabAsElim := false,
declName? := `sandbox,
errToSorry := false
}
let coreM := Meta.MetaM.run' <| Elab.Term.TermElabM.run' (ctx := termElabContext) termElabM
let coreContext: Lean.Core.Context := {
options,
currNamespace := `Example
openDecls := [], -- No 'open' directives needed
fileName := "<stdin>",
fileMap := { source := "", positions := #[0] }
}
match ← (coreM.run' coreContext { env }).toBaseIO with
| .error exception =>
IO.println s!"{← exception.toMessageData.toString}"
| .ok _ => return ()
𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Apr 16 2024 at 22:34):
I guess you are not in a situation where you can simply prepend @
to whatever your input is?
Leni Aniva (Apr 16 2024 at 22:34):
Wojciech Nawrocki said:
I guess you are not in a situation where you can simply prepend
@
to whatever your input is?
The input is user supplied so I don't have control over it
𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Apr 16 2024 at 22:41):
What kinds of inputs are allowed? If the input is someConstant
, you could prepend @
. Is someConstant arg
allowed? In that case, should Lean also not put in any metavariables in the inferred type? For instance if someConstant (a : Nat) {b : Nat} (c : Nat) : a = b := sorry
, do you expect someConstant arg : ∀ {b : Nat}, Nat → 2 = b
(which you'd normally get from @someConstant arg
?
Leni Aniva (Apr 16 2024 at 22:42):
Wojciech Nawrocki said:
What kinds of inputs are allowed? If the input is
someConstant
, you could prepend@
. IssomeConstant arg
allowed? In that case, should Lean also not put in any metavariables in the inferred type? For instance ifsomeConstant (a : Nat) {b : Nat} (c : Nat) : a = b := sorry
, do you expectsomeConstant arg : ∀ {b : Nat}, Nat → 2 = b
(which you'd normallly get from@someConstant arg
?
Yes. The goal here is to not generate any metavariables and infer the type signature of the input
𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Apr 16 2024 at 22:46):
There might be an option in the elaborator that achieves this exact behavior, but I'm not sure what it is. How about traversing the Term
's syntax and prepending the @
to the head function symbol that way?
𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Apr 16 2024 at 22:47):
To be sure, this would break on any custom syntax like infix operators.
Robert Maxton (Apr 17 2024 at 11:30):
Leni Aniva said:
Suppose we have
let e ← match Parser.runParserCategory (env := <- MonadEnv.getEnv) (catName := `term) (input := "Nat.brecOn") (fileName := "<stdin>") with | .ok syn => pure syn | .error error => throwError error let e <- Elab.elabTerm e .none
The inferred type of
e
is a metavariable, but if I replaceNat.brecOn
with@Nat.brecOn
, the inferred type becomes the full type ofNat.brecOn
. How can I enforce this effect during elaboration? I remember in one of the tactics this@
effect is enforced, but I forgot which one
As a side note, if all you want is to a real type instead of a metavariable, you can also use docs#Lean.instantiateMVars or docs#Qq.instantiateMVarsQ as needed.
Leni Aniva (Apr 17 2024 at 18:07):
Robert Maxton said:
Leni Aniva said:
Suppose we have
let e ← match Parser.runParserCategory (env := <- MonadEnv.getEnv) (catName := `term) (input := "Nat.brecOn") (fileName := "<stdin>") with | .ok syn => pure syn | .error error => throwError error let e <- Elab.elabTerm e .none
The inferred type of
e
is a metavariable, but if I replaceNat.brecOn
with@Nat.brecOn
, the inferred type becomes the full type ofNat.brecOn
. How can I enforce this effect during elaboration? I remember in one of the tactics this@
effect is enforced, but I forgot which oneAs a side note, if all you want is to a real type instead of a metavariable, you can also use docs#Lean.instantiateMVars or docs#Qq.instantiateMVarsQ as needed.
I tried calling instantiateMVars
on the mvar produced by elabTerm
but it had no effect
Last updated: May 02 2025 at 03:31 UTC