Zulip Chat Archive
Stream: mathlib4
Topic: max and min delaborators
Patrick Massot (Feb 19 2025 at 16:37):
Nowadays every teaching or propaganda file that I write starts with
open Lean PrettyPrinter Delaborator SubExpr in
@[app_delab Max.max]
def delabMax : Delab := do
let e ← getExpr
guard <| e.isAppOfArity ``Max.max 4
let m := mkIdent `max
let x ← withNaryArg 2 delab
let y ← withNaryArg 3 delab
`($(m) $(x) $(y))
open Lean PrettyPrinter Delaborator SubExpr in
@[app_delab Min.min]
def delabMin : Delab := do
let e ← getExpr
guard <| e.isAppOfArity ``Min.min 4
let m := mkIdent `min
let x ← withNaryArg 2 delab
let y ← withNaryArg 3 delab
`($(m) $(x) $(y))
Is it already somewhere in Mathlib but scoped?
Patrick Massot (Feb 19 2025 at 16:38):
For people who are not used to delaborators: the purpose of this snippet is to bring back max x y
in the infoview instead of the lattice notation for sup.
Floris van Doorn (Feb 19 2025 at 16:39):
I'm quite sure it's not, but I think it would be nice to have as scoped delaborators!
Patrick Massot (Feb 19 2025 at 16:42):
@Kyle Miller do you prefer to fix my delaborators here or on GitHub?
Eric Wieser (Feb 19 2025 at 17:12):
I think these could be unscoped if they tried to synth a LinearOrder
Eric Wieser (Feb 19 2025 at 17:13):
Arguably we should be adjusting the sup
and inf
delaborators to not replace the default one though
Kyle Miller (Feb 19 2025 at 17:31):
Let's make an option that conditionally enables/disables the linked sup/inf delaborators. That will work better than creating a delaborator that creates application syntax
Kyle Miller (Feb 19 2025 at 17:41):
This would mean
- changing those
infix
commands to be equivalentsyntax
es - creating a new option (
pp.mathlib.minMaxAsLattice
?) - writing a delaborator for these notations and make them conditional on the option
For the third point, we can't use an app unexpanders since they currently can't be conditional on options. For the first, we don't currently have infixl:69 (print := false) " ⊓ " => Min.min
notation (but we ought to!)
Jovan Gerbscheid (Apr 01 2025 at 18:16):
Eric Wieser said:
I think these could be unscoped if they tried to synth a
LinearOrder
I've implemented this here: #23558
Kevin Buzzard (Apr 01 2025 at 21:31):
That's very cool but I wonder if it will cause more confusion?
Jovan Gerbscheid (Apr 01 2025 at 21:38):
Well, the status quo is already confusing.
Do you have a suggestion for what to add to the doc-strings to make the new delaborator less confusing?
Eric Wieser (Apr 01 2025 at 21:43):
The docstrings for sup
or for max
?
Floris van Doorn (Apr 01 2025 at 21:44):
It is true that the status quo (with many sup
/inf
lemmas still named using "max"/"min") is confusing.
If we want to keep these naming conventions (which I think we do??) then this delaborator might actually make the lemma names less confusing. I'm getting less skeptical about this delaborator by the minute :-)
Notification Bot (Apr 01 2025 at 21:47):
5 messages were moved here from #mathlib4 > sup
/inf
or max
/min
for set interval lemmas? by Eric Wieser.
Jovan Gerbscheid (Apr 01 2025 at 21:53):
Eric Wieser said:
The docstrings for
sup
or formax
?
Well, any of them. But probably the sup
/inf
one should say something about how its delaborator works? I already gave them new doc-strings in the PR (which don't yet mention the delaboration).
Bhavik Mehta (Apr 01 2025 at 22:11):
Kevin Buzzard said:
That's very cool but I wonder if it will cause more confusion?
cc @Yaël Dillies, since we had exactly the same debate (we landed on the same conclusion that the delaborator was good, provided there's enough documentation about it, but at the time neither of us knew how to write it!). Is it possible for hovering on the notation to mention the delaborator (probably not by name), and the docstring on result of ctrl+click to mention this (whichever of sup
or max
it ends up being)? What I'd love is to give a beginner every opportunity to figure out what's going on by themselves.
Jovan Gerbscheid (Apr 01 2025 at 22:15):
The docstring on the syntax
command is what you see when hovering, and the syntax
command is also where a ctrl+click leads to. So we need that to have a good doc-string.
Eric Wieser (Apr 01 2025 at 22:16):
But of course, we can't have the max
docstring say anything useful, because it lives in core which can't assume that mathlib exists
Eric Wieser (Apr 01 2025 at 22:16):
(or did the extra docstring feature land?)
Kyle Miller (Apr 01 2025 at 23:13):
It's possible to override the hover text of notations these days, in case that's helpful here.
Example code:
import Lean
open Lean PrettyPrinter Delaborator SubExpr
macro "baz " t:term : term => `(id $t)
@[app_delab id]
def delab_baz : Delab := withOverApp 2 do
guard <| ((← getExpr).getArg! 0).isConstOf ``Nat
let some n ← Meta.getNatValue? (← getExpr).appArg! | failure
let nstx ← withAppArg delab
let stx ← annotateCurPos <| ← `(baz $nstx)
addDelabTermInfo (← getPos) stx (← getExpr)
(docString? := s!"This is `baz` applied to the natural number {n}")
return stx
#check id 3
Eric Wieser (Apr 01 2025 at 23:14):
Does this replace the docstring that would be found normally?
Kyle Miller (Apr 01 2025 at 23:14):
Yes
Eric Wieser (Apr 01 2025 at 23:15):
So I guess if you want the original, you should read it from the environment and append?
Kyle Miller (Apr 01 2025 at 23:17):
Yeah, that can be done. For example
@[app_delab id]
def delab_baz : Delab := withOverApp 2 do
guard <| ((← getExpr).getArg! 0).isConstOf ``Nat
let some n ← Meta.getNatValue? (← getExpr).appArg! | failure
let nstx ← withAppArg delab
let stx ← annotateCurPos <| ← `(baz $nstx)
let docString? := (← findDocString? (← getEnv) ``id) |>.map (s!"\n\n----\n\n{·}") |>.getD ""
addDelabTermInfo (← getPos) stx (← getExpr)
(docString? := s!"This is `baz` applied to the natural number {n}.{docString?}")
return stx
Kyle Miller (Apr 01 2025 at 23:17):
A downside to this is that the string will be computed even if it's never actually used
Eric Wieser (Apr 01 2025 at 23:22):
Should docstring?
be changed to be CoreM (Option String)
?
Eric Wieser (Apr 01 2025 at 23:23):
I guess that would make the infotree more than just data...
Kyle Miller (Apr 01 2025 at 23:24):
The docstring here also doesn't need to be dynamic, if there are just a few options. it could be stored on a dummy definition.
Kyle Miller (Apr 01 2025 at 23:27):
import Lean
open Lean PrettyPrinter Delaborator SubExpr
macro "baz " t:term : term => `(id $t)
@[app_delab id]
def delab_baz : Delab := withOverApp 2 do
guard <| ((← getExpr).getArg! 0).isConstOf ``Nat
let some n ← Meta.getNatValue? (← getExpr).appArg! | failure
let nstx ← withAppArg delab
let stx ← annotateCurPos <| ← `(baz $nstx)
let docString? ← findDocString? (← getEnv) (Name.mkSimple s!"baz_docstring_{n}")
addDelabTermInfo (← getPos) stx (← getExpr)
(docString? := docString?)
return stx
/-- This is baz applied to 2. -/
def baz_docstring_2 := ()
/-- This is baz applied to 3. -/
def baz_docstring_3 := ()
#check id 2
#check id 3
Kyle Miller (Apr 01 2025 at 23:28):
It would involve keeping some docstrings in sync though, assuming the idea is to have a docstring for Min/Max that appears in the inf/sup notation.
Jovan Gerbscheid (Apr 01 2025 at 23:29):
What is this idea for de docstring on the inf/sup notation? Can't we just use a normal doc-string on the notation/syntax?
Kyle Miller (Apr 01 2025 at 23:30):
The string could say something like "The infimimum, which is notation for min
when there is no linear order."
Kyle Miller (Apr 01 2025 at 23:32):
I'm just mentioning this to give options. I have no idea if you need it. This lets you make the string depend on any specific information that was acted upon during elaboration.
Jovan Gerbscheid (Apr 01 2025 at 23:39):
In this case we already get a different doc-string for max
(the one from Lean core) and ⊔
(the one from the syntax command) without special support.
Eric Wieser (Apr 02 2025 at 00:07):
Kyle's approach lets you have different docstrings in the infoview and the editor
Eric Wieser (Apr 02 2025 at 00:08):
Which is not necessarily to say that we want that
Jovan Gerbscheid (Apr 02 2025 at 00:39):
I now have the following doc-strings
/--
The supremum/join operation: `x ⊔ y`. It is notation for `max x y`
and should be used when the type is not a linear order.
-/
syntax:68 term:68 " ⊔ " term:69 : term
/--
The infimum/meet operation: `x ⊓ y`. It is notation for `min x y`
and should be used when the type is not a linear order.
-/
syntax:69 term:69 " ⊓ " term:70 : term
And some more explanation in the module doc-string of Mathlib.Order.Notation
.
However, it seems that ctrl+click on the notation sends you to the definition of max
/min
, instead of the ⊔
and ⊓
syntax. :oh_no:
Kyle Miller (Apr 02 2025 at 00:46):
It's unclear whether this is a good idea, but it's possible to override the location for the syntax too:
import Lean
open Lean PrettyPrinter Delaborator SubExpr
/--
Baz
-/
macro (name := bazStx) "baz " t:term : term => `(id $t)
@[app_delab id]
def delab_baz : Delab := withOverApp 2 do
guard <| ((← getExpr).getArg! 0).isConstOf ``Nat
let nstx ← withAppArg delab
let stx ← annotateCurPos <| ← `(baz $nstx)
let module := (← findModuleOf? ``bazStx).getD (← getEnv).mainModule
let some range ← findDeclarationRanges? ``bazStx | failure
let location : DeclarationLocation := { module, range := range.selectionRange }
addDelabTermInfo (← getPos) stx (← getExpr)
(location? := some location)
return stx
#check id 2
Jovan Gerbscheid (Apr 02 2025 at 00:56):
I think this is a good idea for ⊔
and ⊓
notation.
Yaël Dillies (Apr 02 2025 at 08:16):
Kyle, which wizard school did you go to?
Johan Commelin (Apr 02 2025 at 09:17):
It's called MIT, where they teach straight from the wizard book
Patrick Massot (Apr 02 2025 at 09:17):
I heard it’s some school in Boston.
Patrick Massot (Apr 02 2025 at 09:18):
And Johan also heard that rumor and was quicker.
Eric Wieser (Apr 02 2025 at 09:48):
We could go a step further here and make the sup notation (in the source, as opposed to the delaborator) emit a warning if a linear order is found
Jovan Gerbscheid (Apr 02 2025 at 09:50):
Would that be done with a custom delaborator instead of the macro_rules
?
Jovan Gerbscheid (Apr 02 2025 at 09:51):
This would be good as a follow-up PR
Eric Wieser (Apr 02 2025 at 10:45):
elaborator, yes
Jovan Gerbscheid (Apr 02 2025 at 10:50):
I added the withGoToDef
function
/-- Annotate the syntax `stx` with the go-to-def information of `target`. -/
def withGoToDef (stx : Term) (target : Name) : DelabM Term := do
let stx ← annotateCurPos stx
let module := (← findModuleOf? target).getD (← getEnv).mainModule
let some range ← findDeclarationRanges? target | failure
let location := { module, range := range.selectionRange }
addDelabTermInfo (← getPos) stx (← getExpr) (location? := some location)
return stx
And used it to have the ⊔
and ⊓
go to their notation when ctrl+clicking in the infoview. On the other hand, when ctrl+clicking in the editor, it leads to the macro_rules
.
Jovan Gerbscheid (Apr 02 2025 at 10:56):
When hovering over a ⊔ b
, the pop-up shows something like @max α SemilatticeSup.toMax a b : α
, so you can still ctrl+click on the @max
if you want.
Jovan Gerbscheid (Apr 18 2025 at 11:12):
Is this still waiting for something? @Kyle Miller, I think you have been assigned as a maintainer. (#23558)
Last updated: May 02 2025 at 03:31 UTC