Zulip Chat Archive
Stream: Is there code for X?
Topic: Extend getParamNames
Yicheng Tao (Nov 18 2024 at 12:29):
I was working on extracting the arg array of a constant. I found the function getParamNames
in the library.
/-- Return the parameter names for the given global declaration. -/
def getParamNames (declName : Name) : MetaM (Array Name) := do
forallTelescopeReducing (← getConstInfo declName).type fun xs _ => do
xs.mapM fun x => do
let localDecl ← x.fvarId!.getDecl
return localDecl.userName
I was trying to make it return not only the userName, but also the type. But the types that depending on local variable appears in the form like _uniq.3
if I simply use localDecl.type
.
How to do it correctly?
Eric Wieser (Nov 18 2024 at 13:02):
Can you un- #xy ?
Yicheng Tao (Nov 18 2024 at 13:24):
I have the fullname of a constant and an Environment
. What I want to get is the arg array of that constant.
E.g.:
theorem test {P Q : Prop} (p : P) : P := p
I have the fullname test
and the environment. I want the desired function getParam
to return the arg array as #[(P, Prop), (Q, Prop), (p, P)]
. The signature of the function would be Name -> Array (String × String)
.
Daniel Weber (Nov 19 2024 at 04:49):
If you want to obtain a string you should take a look at docs#Lean.PrettyPrinter.Delaborator.delabConstWithSignature
Yicheng Tao (Nov 19 2024 at 04:59):
Daniel Weber said:
If you want to obtain a string you should take a look at docs#Lean.PrettyPrinter.Delaborator.delabConstWithSignature
I found doc-gen4 also use delaborator, but it will exceed time limit for some constants. I'm looking for some other way.
Daniel Weber (Nov 19 2024 at 05:01):
I don't think there are other ways to convert an Expr
to a String
(assuming you don't want to output the whole expression), perhaps you can find the Syntax
where it's defined, but that'll be problematic with variable
, local notation
, etc.
Yicheng Tao (Nov 19 2024 at 06:04):
Too bad. I didn't expect it to be that complicated.
Daniel Weber (Nov 19 2024 at 06:05):
Why does the delaborator time out? Do you have a #mwe?
Yicheng Tao (Nov 19 2024 at 06:38):
It's hard to extract a #mwe from my code. I was modifying the ExtractData.lean
script from LeanDojo. It processes the files in Mathlib one by one. Here is some relevant code:
import Lean
import Lake
namespace DocGen
open Lean Widget Meta
/--
Stores information about a typed name.
-/
structure NameInfo where
/--
The name that has this info attached.
-/
name : Name
/--
The pretty printed type of this name.
-/
type : CodeWithInfos
deriving Inhabited
/--
An argument to a declaration, e.g. the `(x : Nat)` in `def foo (x : Nat) := x`.
-/
structure Arg where
/--
The pretty printed binder syntax itself.
-/
binder : CodeWithInfos
/--
Whether the binder is implicit.
-/
implicit : Bool
/--
A base structure for information about a declaration.
-/
structure Info extends NameInfo where
/--
The list of arguments to the declaration.
-/
args : Array Arg
deriving Inhabited
/--
Pretty prints a `Lean.Parser.Term.bracketedBinder`.
-/
private def prettyPrintBinder (stx : Syntax) (infos : SubExpr.PosMap Elab.Info) : MetaM Widget.CodeWithInfos := do
let fmt ← PrettyPrinter.format Parser.Term.bracketedBinder.formatter stx
let tt := Widget.TaggedText.prettyTagged fmt
let ctx := {
env := ← getEnv
mctx := ← getMCtx
options := ← getOptions
currNamespace := ← getCurrNamespace
openDecls := ← getOpenDecls
fileMap := default,
ngen := ← getNGen
}
return Widget.tagCodeInfos ctx infos tt
private def prettyPrintTermStx (stx : Term) (infos : SubExpr.PosMap Elab.Info) : MetaM Widget.CodeWithInfos := do
let fmt ← PrettyPrinter.formatTerm stx
let tt := Widget.TaggedText.prettyTagged fmt
let ctx := {
env := ← getEnv
mctx := ← getMCtx
options := ← getOptions
currNamespace := ← getCurrNamespace
openDecls := ← getOpenDecls
fileMap := default,
ngen := ← getNGen
}
return Widget.tagCodeInfos ctx infos tt
def Info.ofConstantVal (v : ConstantVal) : MetaM Info := do
let e := Expr.const v.name (v.levelParams.map mkLevelParam)
println! s!"{v.name}"
-- Use the main signature delaborator. We need to run sanitization, parenthesization, and formatting ourselves
-- to be able to extract the pieces of the signature right before they are formatted
-- and then format them individually.
let (sigStx, infos) ← PrettyPrinter.delabCore e (delab := PrettyPrinter.Delaborator.delabConstWithSignature)
let sigStx := (sanitizeSyntax sigStx).run' { options := (← getOptions) }
let sigStx ← PrettyPrinter.parenthesize PrettyPrinter.Delaborator.declSigWithId.parenthesizer sigStx
let `(PrettyPrinter.Delaborator.declSigWithId| $_:term $binders* : $type) := sigStx
| throwError "signature pretty printer failure for {v.name}"
let args ← binders.mapM fun binder => do
let fmt ← prettyPrintBinder binder infos
return Arg.mk fmt (!binder.isOfKind ``Parser.Term.explicitBinder)
let type ← prettyPrintTermStx type infos
return {
toNameInfo := { name := v.name, type },
args,
}
end DocGen
...
/--
Extract premise information from `TermInfo` in `InfoTree`.
-/
private def visitTermInfo (ti : TermInfo) (env : Environment) : TraceM Unit := do
let some fullName := ti.expr.constName? | return ()
let fileMap ← getFileMap
let some const := env.constants.find? fullName | return ()
let info ← withEnv env $ DocGen.Info.ofConstantVal const.toConstantVal
let args := info.args.map (fun arg => arg.binder.pretty)
let type := info.type.pretty
...
This is only part of the code. The process visits every term in that file. I just try to print the constant which caused the time out, but I found that it succeeds when be processed individually. I guess the delaborator's time may be accumulated when processing the whole file?
Yicheng Tao (Nov 19 2024 at 06:39):
I wonder how to set the maxHeartbeats to be higher. The default is 200000 and I failed to set it with set_option
.
Yicheng Tao (Nov 19 2024 at 06:56):
Here is the error message:
uncaught exception: (deterministic) timeout at `delab`, maximum number of heartbeats (200000) has been reached
Use `set_option maxHeartbeats <num>` to set the limit.(invalid MessageData.lazy, missing context)
Damiano Testa (Nov 19 2024 at 06:59):
What is the error when you try, say set_option maxHeartbeats 0
?
Yicheng Tao (Nov 19 2024 at 07:04):
set_option maxHeartbeats
doesn't work. The scripts is a independent file in the project and is ran by using lake env lean --run
.
Yicheng Tao (Nov 19 2024 at 07:04):
It seems that this option should be passed in another way.
Damiano Testa (Nov 19 2024 at 07:06):
You should place it in the file where you want it to take effect and its effect start from the set_option
line.
Damiano Testa (Nov 19 2024 at 07:07):
You can limit it to the next declaration via set_option ... in <command>
.
Yicheng Tao (Nov 19 2024 at 07:10):
Oh I found the place where I can modify the config.
Yicheng Tao (Nov 19 2024 at 07:10):
For someone who may be interested:
let (trace, _) ← traceM.run'.toIO {fileName := s!"{path}", fileMap := FileMap.ofString input, maxHeartbeats := 2000000000} {env := env}
Yicheng Tao (Nov 19 2024 at 07:11):
And it's weird that the 2000000000
here seems to be 2000000
in error message.
Damiano Testa (Nov 19 2024 at 07:17):
There are two "levels" of heartBeats: an "internal" one that is more fine-grained and a "user-facing" one that is <internal>/10^3
.
Last updated: May 02 2025 at 03:31 UTC