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