Zulip Chat Archive
Stream: metaprogramming / tactics
Topic: Simulating the scope of an inductive declaration in MetaM
nrs (Dec 17 2024 at 19:01):
I'm trying to debug why info view and trace.Elab
and trace.Meta
are reporting a different metavariable context (full context is available here: #lean4 > Elab doesn't match infoview?), and for that reason I'm trying to simulate the partially elaborated context when my cursor is located at ... (inj...
in the following inductive declaration:
inductive IArithExprSymbols {sig : Signature} [inst : SubSig NatTyE sig] : W sig -> Type _
| val : Nat -> IArithExprSymbols (inject _)
There are a couple of approaches I've tried so far:
inductive test [SubSig NatTyE sig]: W sig -> Type _
| val : Nat -> by run_tac do
let lctx <- getLCtx
lctx.forM (fun ldecl => do
if ldecl.isImplementationDetail then pure _
else dbg_trace ldecl)
let mctx <- getMCtx
Lean.Elab.Tactic.evalTactic (<- `(tactic|exact test (inject ⟨_, _⟩)))
The above isn't ideal because the run_tac
sequence messes up the metavariable context. Multiple of the trace.Meta.isDefEq
reports from the vanilla trace get jumbled up and it seems to me that so does the evaluation order.
Attempting to use the following will fail because the declaration must be equivalent to a totally elaborated term in order to add it to the environment, and we're interested in a partial context.
run_meta do
let newdecl := Lean.Declaration.inductDecl
( lparams := [] )
( nparams := 0 )
[
{ name := `testInductiveType,
type := .sort (.succ .zero),
ctors := [
.mk `mk (.forallE `x (.const `Nat []) (.const `testb []) .default),
.mk `nil (.const `testInductiveType [])
]}]
.false
discard <| compileDecl newdecl
Any suggestions? My next attempt will involve declaring a scope with axioms and seeing how I can bind a goal to simulate the partial target (strictly speaking we're not in TacticM
but withLocalDecl
is maybe how to do it?), something starting like:
axiom IArithExprSymbols {sig : Signature} [inst : SubSig NatTyE sig] : W sig -> Type _
example : W sig := by _
nrs (Dec 17 2024 at 19:05):
I'll also be testing out
inductive IArithExprSymbols {sig : Signature} [inst : SubSig NatTyE sig] : W sig -> Type _
| val : Nat -> by_elab do ...
nrs (Dec 17 2024 at 19:28):
my worry with the axiom ...; example ...
method is that the reports from the infoview and trace actually come from trying to elaborate and typecheck the recursor, can anyone confirm?
nrs (Dec 17 2024 at 19:39):
wrt this last comment, evidence that this could be true is that the following definition will actually report a type mismatch at the recursor level instead of complaining with what I think would usually be `(kernel) arg #n of ... contains a non valid occurrence of the datatypes being declared
structure Signature where
symbols : Type
arity : symbols -> Nat
inductive Ext' (sig : Signature) (α : Type _)
| mk : (s : sig.symbols) -> Vector3 α (sig.arity s) -> Ext' sig α
inductive W' (sig : Signature)
| sup : Ext' sig (W' sig) -> (W' sig)
edit: in the above example, elab info trace suggests that the the following two terms are elaborated first before the recursor is constructed, so the desired scope to simulate is the one happening during the elaboration of exactly these (ofc with the adequate changes to model the declaration of IArithExprSymbols
)
Wc (isBinder := true) : Signature → Type
@Wc.sup (isBinder := true) : {sig : Signature} → Ext' sig (Wc sig) → Wc sig
nrs (Dec 17 2024 at 21:14):
update: the code and traces in the following explain what's going on. the term in the inductive scope goes through a second round of elaboration, in this case Lean.Term.elabAnonymousCtor
. so using axiom ...; example ...
alone are not enough to simulate an inductive declaration, unless your term is fully explicit!
this explains the difference seen in the original topic: below the first declaration typechecks while the second doesn't, and one would be mystified at why looking only at trace.Elab.step
(or the beginning of trace.Elab.info
) because it does not report the additional elaboration undergone by the term in the inductive scope! the entirety oftrace.Elab.info
however will
structure Signature where
symbols : Type
arity : symbols -> Nat
inductive Ext (sig : Signature) (α : Type _)
| mk : (s : sig.symbols) -> (Fin2 (sig.arity s) -> α) -> Ext sig α
class SubSig' (siga : Signature) (sigb : outParam Signature) where
inj : Ext siga α -> Ext sigb α
set_option pp.explicit true
set_option trace.Elab.step.result true
inductive IArithExprSymbols' {sig : Signature} [inst : SubSig' NatTyE sig] : W sig -> Type _
| val : Nat -> @IArithExprSymbols' sig inst ⟨_, _⟩
-- [Elab.step.result] Nat → @IArithExprSymbols' sig inst (@W.sup sig (@Ext.mk sig (W sig) ?m.1941 ?m.1942))
#print IArithExprSymbols'.val
/-
constructor myNamespace.IArithExprSymbols'.val.{u_1} : {sig : Signature} →
[inst : SubSig' NatTyE sig] →
{x : sig.symbols} →
{x_1 : Fin2 (sig.arity x) → W sig} → Nat → @IArithExprSymbols' sig inst (@W.sup sig (@Ext.mk sig (W sig) x x_1))
-/
axiom IArithExprSymbols'' {sig : Signature} [inst : SubSig' NatTyE sig] : W sig -> Type _
def val {sig : Signature} [inst : SubSig' NatTyE sig] : Type _ := Nat -> @IArithExprSymbols'' sig inst ⟨_, _⟩
-- [Elab.step.result] Nat → @IArithExprSymbols'' sig inst (@W.sup sig (@Ext.mk sig (W sig) ?m.2405 ?m.2406))
#print val
/-
def myNamespace.val.{u_1, u_2} : {sig : Signature} → [inst : SubSig' NatTyE sig] → Type u_2 :=
@sorryAx ({sig : Signature} → [inst : SubSig' NatTyE sig] → Type u_2) true
-/
nrs (Dec 17 2024 at 21:32):
furthermore, knowing this is important to debug typeclass synthesis (as was our initial interest) because in the inductive
declaration, the synthesis only succeeds after the second round of elaboration!
Last updated: May 02 2025 at 03:31 UTC