Zulip Chat Archive
Stream: lean4
Topic: A version of check displaying only explicit arguments.
Patrick Massot (Jul 01 2025 at 09:02):
I would be very grateful if some meta-programming guru could write a version of the #check command that shows only explicit argument. This week Iβm spending a significant portion of my time staring at things like
MDifferentiableAt.clm_apply_of_inCoordinates.{u_1, u_2, u_3, u_4, u_5, u_6, u_7, u_8, u_9, u_10, u_11, u_12, u_13, u_14}
{π : Type u_1} {Fβ : Type u_2} {Fβ : Type u_3} {Bβ : Type u_4} {Bβ : Type u_5} {M : Type u_6} {Eβ : Bβ β Type u_7}
{Eβ : Bβ β Type u_8} [NontriviallyNormedField π] [(x : Bβ) β AddCommGroup (Eβ x)] [(x : Bβ) β Module π (Eβ x)]
[NormedAddCommGroup Fβ] [NormedSpace π Fβ] [TopologicalSpace (TotalSpace Fβ Eβ)] [(x : Bβ) β TopologicalSpace (Eβ x)]
[(x : Bβ) β AddCommGroup (Eβ x)] [(x : Bβ) β Module π (Eβ x)] [NormedAddCommGroup Fβ] [NormedSpace π Fβ]
[TopologicalSpace (TotalSpace Fβ Eβ)] [(x : Bβ) β TopologicalSpace (Eβ x)] {EBβ : Type u_9} [NormedAddCommGroup EBβ]
[NormedSpace π EBβ] {HBβ : Type u_10} [TopologicalSpace HBβ] {IBβ : ModelWithCorners π EBβ HBβ} [TopologicalSpace Bβ]
[ChartedSpace HBβ Bβ] {EBβ : Type u_11} [NormedAddCommGroup EBβ] [NormedSpace π EBβ] {HBβ : Type u_12}
[TopologicalSpace HBβ] {IBβ : ModelWithCorners π EBβ HBβ} [TopologicalSpace Bβ] [ChartedSpace HBβ Bβ] {EM : Type u_13}
[NormedAddCommGroup EM] [NormedSpace π EM] {HM : Type u_14} [TopologicalSpace HM] {IM : ModelWithCorners π EM HM}
[TopologicalSpace M] [ChartedSpace HM M] [FiberBundle Fβ Eβ] [VectorBundle π Fβ Eβ] [FiberBundle Fβ Eβ]
[VectorBundle π Fβ Eβ] {bβ : M β Bβ} {bβ : M β Bβ} {mβ : M} {Ο : (m : M) β Eβ (bβ m) βL[π] Eβ (bβ m)}
{v : (m : M) β Eβ (bβ m)}
(hΟ :
MDifferentiableAt IM π(π, Fβ βL[π] Fβ) (fun m β¦ inCoordinates Fβ Eβ Fβ Eβ (bβ mβ) (bβ m) (bβ mβ) (bβ m) (Ο m)) mβ)
(hv : MDifferentiableAt IM (IBβ.prod π(π, Fβ)) (fun m β¦ { proj := bβ m, snd := v m }) mβ)
(hbβ : MDifferentiableAt IM IBβ bβ mβ) :
MDifferentiableAt IM (IBβ.prod π(π, Fβ)) (fun m β¦ { proj := bβ m, snd := (Ο m) (v m) }) mβ
trying to spot what are the arguments Iβm meant to give explicitly. Note that an option to tell #check to remove universes would also be nice. It would be even greater to have an option asking for tooltips to show only explicit arguments, but Iβm probably getting too excited here.
Patrick Massot (Jul 01 2025 at 09:08):
I donβt even understand why
namespace Lean.Elab.Command
open Meta
elab "#check'" x:term : command => do
withoutModifyingEnv <| runTermElabM fun _ => Term.withDeclName `_check do
let e β Term.elabTerm x none
Term.synthesizeSyntheticMVarsNoPostponing (ignoreStuckTC := true)
Meta.check e
let e β Term.levelMVarToParam (β instantiateMVars e)
if e.isSyntheticSorry then
return
let type β inferType e
logInfo m!"{e} : {type}"
end Lean.Elab.Command
does not reproduce what #check is doing in the above example.
Aaron Liu (Jul 01 2025 at 10:10):
#check has special support for identifiers
Joachim Breitner (Jul 01 2025 at 10:17):
You want to see only explicit parameters, right?
Aaron Liu (Jul 01 2025 at 10:29):
If you do #check (MDifferentiableAt.clm_apply_of_inCoordinates) then it fills in the implicit arguments with metavariables
Patrick Massot (Jul 01 2025 at 10:30):
Iβm not sure what is the difference between arguments and parameters. In the above example Iβd like to see
MDifferentiableAt.clm_apply_of_inCoordinates
(hΟ : MDifferentiableAt IM π(π, Fβ βL[π] Fβ) (fun m β¦ inCoordinates Fβ Eβ Fβ Eβ (bβ mβ) (bβ m) (bβ mβ) (bβ m) (Ο m)) mβ)
(hv : MDifferentiableAt IM (IBβ.prod π(π, Fβ)) (fun m β¦ { proj := bβ m, snd := v m }) mβ)
(hbβ : MDifferentiableAt IM IBβ bβ mβ) :
MDifferentiableAt IM (IBβ.prod π(π, Fβ)) (fun m β¦ { proj := bβ m, snd := (Ο m) (v m) }) mβ
Aaron Liu (Jul 01 2025 at 10:33):
Do you want it on only identifiers?
Kyle Miller (Jul 01 2025 at 10:46):
An idea: use the signature delaborator directly and then filter out the implicit binder syntaxes.
Here's a hint for the new interface for that: https://github.com/leanprover/doc-gen4/pull/302/files#diff-2cee00262515d0d1209747d4bb2dbec5423900de5ec0ab9f286446e02eb96090R54
If you use the right kind of messagedata, there's a way to pass along the infos
Patrick Massot (Jul 01 2025 at 10:48):
Aaron Liu said:
Do you want it on only identifiers?
This would already be very useful. Of course more is better.
Aaron Liu (Jul 01 2025 at 10:49):
I'm asking because if you try it on a general term then elabTerm will fill them in with metavariables first
Aaron Liu (Jul 01 2025 at 10:50):
Anyways here's what I came up with
import Mathlib
namespace Lean.Elab.Command
open Meta
elab "#check'" x:term : command => do
withoutModifyingEnv <| runTermElabM fun _ => Term.withDeclName `_check' do
let e β Term.elabTerm x none
Term.synthesizeSyntheticMVarsNoPostponing (ignoreStuckTC := true)
Meta.check e
let mut e β Term.levelMVarToParam (β instantiateMVars e)
if e.isSyntheticSorry then
return
let mut type β instantiateMVars (β inferType e)
-- for tracking the context, since it seems complicated to do it myself I have a metavariable do it for me
let mut mvar β mkFreshExprMVar (some type)
repeat do
let .forallE n t b bi := type | break
if let .default := bi then break
(type, mvar, e) β mvar.mvarId!.withContext do withLocalDecl n bi t fun v => do
let e := .app e v
let type := b.instantiate1 v
let mvar β mkFreshExprMVar (some type)
return (type, mvar, e)
mvar.mvarId!.withContext do logInfo m!"{e} : {type}"
end Lean.Elab.Command
#check' @MDifferentiableAt.clm_apply_of_inCoordinates
Patrick Massot (Jul 01 2025 at 10:53):
Thanks, itβs very encouraging but does not use delaborators, so the output is pretty hard to read.
Aaron Liu (Jul 01 2025 at 10:53):
What do you mean by that?
Aaron Liu (Jul 01 2025 at 10:53):
Do you want to use the signature delaborator?
Kyle Miller (Jul 01 2025 at 10:56):
I'm pretty sure Patrick wants what check does, but skip the implicit binders
Patrick Massot (Jul 01 2025 at 10:56):
Oh no, this is simply a missing open Manifold, sorry about the noise.
Patrick Massot (Jul 01 2025 at 10:57):
But it would still be nicer to have the argument names instead of a chain of implications.
Kyle Miller (Jul 01 2025 at 11:03):
Iirc, MessageData.ofFormatWithInfos is the other piece to the puzzle, given the interface in the linked diff, for how to print the result and get it hoverable. If you copy some of the delabConst and declSigId logic from the core signature delaborator, you can get the constant in there too. (On my phone)
Eric Wieser (Jul 01 2025 at 11:04):
Could there be a pp option to show all arrows as named binders, if they have a name? That is, show β β β as (n : β) β β etc
Kyle Miller (Jul 01 2025 at 11:12):
Every arrow has a name though, but presence of macro scopes is a reasonable indication of being intentional.
There's a secret inaccessible pp option for this, used by the signature delaborator to do exactly this after the colon. https://github.com/leanprover/lean4/blob/8424ddbb3edf4c3b440d0c4e1216e3ebf19bdaf4/src/Lean/PrettyPrinter/Delaborator/Builtins.lean#L950
Aaron Liu (Jul 01 2025 at 11:14):
there are secret pp options?
Kyle Miller (Jul 01 2025 at 12:10):
import Lean
open Lean Elab Command PrettyPrinter Delaborator in
elab tk:"#check' " name:ident : command => runTermElabM fun _ => do
for c in (β realizeGlobalConstWithInfos name) do
addCompletionInfo <| .id name name.getId (danglingDot := false) {} none
let info β getConstInfo c
let delab : Delab := do
delabForallParamsWithSignature fun binders type => do
let binders := binders.filter fun binder => binder.raw.isOfKind ``Parser.Term.explicitBinder
return β¨β `(declSigWithId| $(mkIdent c) $binders* : $type)β©
logInfoAt tk <| .ofFormatWithInfosM (PrettyPrinter.ppExprWithInfos (delab := delab) info.type)
#check' id
-- id (a : Ξ±) : Ξ±
Patrick Massot (Jul 01 2025 at 16:09):
Great, thanks!
Last updated: Dec 20 2025 at 21:32 UTC