Zulip Chat Archive
Stream: lean4
Topic: check output
Patrick Massot (May 23 2023 at 13:59):
Is there any reason why
variable (f : Nat → Nat)
#check f
gives the expected output Nat → Nat but
def addOne : Nat → Nat := fun x ↦ x + 1
#check addOne
prints a weird addOne (a✝ : Nat) : Nat?
Kyle Miller (May 23 2023 at 14:01):
There's a special case in #check where if the expression is a constant then it uses a different pretty printer that tries to format it like a function definition.
Eric Wieser (May 23 2023 at 14:01):
#check (addOne) gives the behavior you expect
Kyle Miller (May 23 2023 at 14:01):
If you do #check @addOne you can trick it into not doing that
Kyle Miller (May 23 2023 at 14:02):
Parentheses instantiate implicit arguments with metavariables, which might not be what you want.
Patrick Massot (May 23 2023 at 14:03):
But why does #check do that to me?
Eric Wieser (May 23 2023 at 14:05):
Because of this thread:
Sebastian Ullrich said:
In lean4#1943, I made a suggestion not directly related to the PR:
In fact I would probably go further and just make
#check $n:identa semantically separate command that shows the signature ofnwithout elaboration - I can't be the only one that usually starts with#check toStringand then only remembers to add the@on the second try.How do people use
#checkaround here? Would it be a welcome change if#check toStringprintedToString.toString.{u} {α : Type u} [self : ToString α] (a : α) : String(using the fancy new signature pretty printer) instead of
toString : ?m.1632 → Stringeven if it is not perfectly consistent with the more general meaning "show type of this term" of
#check?
Patrick Massot (May 23 2023 at 14:06):
Well, I guess I understand how it is useful in real situations. It's simply inconvenient in early teaching.
Kyle Miller (May 23 2023 at 14:12):
Here's an override using the standard type signature rather than the fancy one:
open Lean Elab Command Meta in
elab_rules : command
  | `(command| #check%$tk $term) => withoutModifyingEnv <| runTermElabM fun _ => Elab.Term.withDeclName `_check do
    if let `($_:ident) := term then
      try
        for c in (← resolveGlobalConstWithInfos term) do
          let decl ← getConstInfo c
          addCompletionInfo <| .id term c (danglingDot := false) {} none
          logInfoAt tk m!"{c} : {decl.type}"
          return
      catch _ => pure ()  -- identifier might not be a constant but constant + projection
    let e ← Term.elabTerm term none
    Term.synthesizeSyntheticMVarsNoPostponing
    let e ← Term.levelMVarToParam (← instantiateMVars e)
    let type ← inferType e
    if e.isSyntheticSorry then
      return
    logInfoAt tk m!"{e} : {type}"
#check addOne
-- addOne : Nat → Nat
Kyle Miller (May 23 2023 at 14:12):
Maybe the real #check could have an option for how fancy it should be?
Gabriel Ebner (May 23 2023 at 17:25):
You can override the command much more easily. :smile:
macro_rules
  | `(#check ($_)) => Lean.Macro.throwUnsupported
  | `(#check%$tk $term) => `(#check%$tk ($term))
Kyle Miller (May 23 2023 at 17:26):
That gives different output -- it instantiates the implicit arguments
Kyle Miller (May 23 2023 at 17:27):
macro_rules
  | `(#check @$_) => Lean.Macro.throwUnsupported
  | `(#check $term) => `(#check @$term)
This would be closer, but it prepends @ to the name in the output
Mario Carneiro (May 23 2023 at 17:40):
arguably it is more correct/consistent to put the @ on the name
Eric Wieser (May 23 2023 at 17:43):
Lean3 doesn't do so when you hover over a name in the editor
Mario Carneiro (May 23 2023 at 17:47):
yes but that's the signature pretty printer, which as we have established has its own rules
Mario Carneiro (May 23 2023 at 17:47):
the desired behavior here seems to be expr : type and for that you want to print expr in such a way that it is at least plausibly re-parseable
Mario Carneiro (May 23 2023 at 17:48):
which means putting @ if there is an unapplied implicit arg
Last updated: May 02 2025 at 03:31 UTC