Zulip Chat Archive
Stream: mathlib4
Topic: linter requests
Matthew Ballard (Aug 21 2024 at 09:25):
Perhaps a separate topic to record these is useful?
I have one: a linter that warns you if you are building data using tactics.
Damiano Testa (Aug 21 2024 at 10:46):
Oh, this could leverage a lot of the have
vs let
linter.
Joseph Tooby-Smith (Aug 21 2024 at 10:54):
Maybe this is not possible or already exists, but I would love to have a linter that checks for pointless parentheses (i.e. pairs of parentheses that can be deleted with no ill effect).
Damiano Testa (Aug 21 2024 at 10:57):
Linters can do a lot of things and this is certainly in scope!
Damiano Testa (Aug 21 2024 at 10:58):
There is a "pedantic" linter in the works that checks how closely your code matches the output of pretty-printing it. I suspect that unnecessary parenthesie are there too, but there is a lot. (#15535)
Michael Rothgang (Aug 21 2024 at 12:41):
#15941 looks at some of its warnings on mathlib: help fixing these (if appropriate) or merging some of the fixes is welcome.
Violeta Hernández (Aug 23 2024 at 02:10):
Would it be possible to have a linter for putting hypotheses in variable
? From what I understand doing so is not ideal
Yaël Dillies (Aug 23 2024 at 06:15):
It would, but I have argued it is ideal in some situations
Violeta Hernández (Aug 27 2024 at 12:08):
Here's another idea: a linter for using Type
instead of Type*
Michael Rothgang (Aug 27 2024 at 13:44):
One a linter when using Type _
instead of Type*
. (This was discussed before; in a calm moment, I'll edit in the link.)
Adomas Baliuka (Aug 27 2024 at 22:48):
Just for completeness sake: "a linter that flags unwanted unicode".
I have no idea how to implement it technically (been reading the metaprogramming book but not sure how to parse individual characters) and also there would need to be some discussion about what "unwanted" should be. (My suggestion would be "everything that's not on a whitelist, which can grow over time").
Previously discussed here
Michael Rothgang (Aug 28 2024 at 08:45):
Adomas Baliuka said:
Just for completeness sake: "a linter that flags unwanted unicode".
I have no idea how to implement it technically (been reading the metaprogramming book but not sure how to parse individual characters) and also there would need to be some discussion about what "unwanted" should be. (My suggestion would be "everything that's not on a whitelist, which can grow over time").
Previously discussed here
In terms of infrastructure, you could certainly piggy-back on the text-based linters in Mathlib.Tactic.Linter.TextBased
(or try to use a syntax linter... but that might be harder/you may have to distinguish more cases). The former are text-based, so have no understanding of Lean syntax (in particular, the linter would also complain about using unicode symbols in comments etc., which might actually be fine).
Or is your question more about the "splitting the string into unicode codepoints"?
Michael Rothgang (Aug 28 2024 at 08:46):
(Though, searching for "is this a substring" hopefully would side-step this question.)
Adomas Baliuka (Aug 28 2024 at 10:15):
(deleted)
Michael Rothgang (Aug 28 2024 at 10:18):
Looks like a reasonable start. Perhaps the following is obvious to you (in that case, please proceed), otherwise:
- you need to define a
newUnicode
variant of the styleError - you should add your linter to
allLinters
- Right now, your check is not quite what we want, as it would also complain about the letter
a
, the number0
or some common symbols. But the idea works.
Michael Rothgang (Aug 28 2024 at 10:18):
(Edit: I see you deleted your post now. It contained a start towards linting against the above.)
Adomas Baliuka (Aug 28 2024 at 10:21):
@Michael Rothgang Thanks! I deleted because I didn't want to hijack this thread and, as you said, had to do some more modifications that cannot be usefully shortened into what could be posted here. I think I will just make a PR and see what happens.
Violeta Hernández (Sep 03 2024 at 00:22):
How about: linter for theorem and instance names that are too long!
Violeta Hernández (Sep 03 2024 at 00:24):
We've got a bunch of bad autogenerated instance names like docs#NumberField.instIsLocalizedModuleIntNonZeroDivisorsSubtypeMemSubmoduleRingOfIntegersCoeToSubmoduleValFractionalIdealRestrictScalarsSubtype, which are so long you can't even call them explicitly without triggering the long line linter
Violeta Hernández (Sep 03 2024 at 00:24):
And they clutter search results on the docs
Yaël Dillies (Sep 03 2024 at 06:08):
Violeta, you have no idea what instance names we had when you were away :face_with_hand_over_mouth:
Rida Hamadani (Sep 03 2024 at 06:13):
I still come across the old instance names while searching for lemmas on moogle.ai, some of those can fill my whole screen!
Tristan Figueroa-Reid (Feb 03 2025 at 07:04):
Would collapsing subsequent calls of subst
be a good linter? (Are there any linters that look at adjacent tactic calls at all, like collapsing rw/rwa ...
and assertion
to rwa
?)
Damiano Testa (Feb 03 2025 at 09:48):
A brief check suggests that there are about 15 files containing consecutive subst
s.
Damiano Testa (Feb 03 2025 at 09:48):
In terms of actual implementation of the linter, I do not think that there are already linters that check consecutive tactics "syntactically". There are some linters that track metavariables, looking for two tactics modifying a given goal in sequence (possibly with some different intervening tactics in-between). If you decide to do the metavariable-tracking, then the linter will be quite a bit more involved.
Damiano Testa (Feb 03 2025 at 09:48):
Here are a couple of examples of some straightforward and not-so-straightforward lints:
example {a b c} (ha : a = 0) (hb : b = 0) (hc : c = 0) : a = b + c := by
subst ha
subst hb
subst hc
rfl
example {a b c} (ha : a = 0) (hb : b = 0) (hc : c = 0) : a = b + c := by
subst ha; subst hb
subst hc
rfl
example {a b c} (ha : a = 0) (hb : b = 0) (hc : c = 0) : a = b + c := by
subst ha
apply id
subst hb hc
rfl
example {a b} (ha : a = 0) (hb : b = 0) : a = b ∧ True := by
constructor
subst ha
case right =>
trivial
subst hb
rfl
Damiano Testa (Feb 03 2025 at 09:48):
Some of the subst
s above are "syntactically" consecutive, others are "semantically" consecutive.
Damiano Testa (Feb 03 2025 at 09:48):
There are some ongoing discussions about general linter performances, but the idea of collapsing consecutive subst
s seems reasonable. Still, unless this is intended mostly as a learning exercise, try to gather some support, since every new linter means adding more potential warnings and there is a fine balance between being useful and being annoying!
Damiano Testa (Feb 03 2025 at 09:48):
There are a few linters that maybe should not be running constantly, but rather every once in a while in an automated process and I think that this linter would be one of them: it is rare to have consecutive subst
s, so having the linter constantly running may be a little wasteful, but it is also good to clean up code, even if "after the fact".
Damiano Testa (Feb 03 2025 at 09:48):
This kind of periodic clean up is not automated, but I have been thinking about it for some time and would like to see it implemented.
Bolton Bailey (Feb 03 2025 at 18:08):
Tristan Figueroa-Reid said:
Would collapsing subsequent calls of
subst
be a good linter? (Are there any linters that look at adjacent tactic calls at all, like collapsingrw/rwa ...
andassertion
torwa
?)
I have added this to the wishlist, along with some of the earlier suggestions @Violeta Hernández and @Matthew Ballard made, hope that's all right.
Michael Rothgang (Mar 10 2025 at 14:18):
My wish for today: write a "low-level performance optimisation tactic linter", which tries to replace one tactic with a "faster" one if that is possible. Let's use the replacement "continuity -> fun_prop" as an example. This cannot always be done, but if it can, fun_prop is usually faster (sometimes by a lot). This linter would tell you "this continuity call can be replaced by fun_prop" could be useful.
More specifically, I'm thinking of a syntax linter which does the following, for every pair (slower_tactic, faster_tactic)
.
- look for occurrences of the
slower_tactic
tactic- careful: do ignore default parameters
- occurrences inside proofs (of theorems, instances or definitions) should be fine
- try to replace this by the
faster_tactic
tactic - elaborate the result: if there are no errors, print a message about the replacement. Otherwise, do nothing.
As a start, the pair (continuity, fun_prop)
and (measurability, fun_prop)
could be a start.
Michael Rothgang (Mar 10 2025 at 14:18):
@Damiano Testa In case you're bored and want to write a performance-enhancing linter instead :-)
Damiano Testa (Mar 10 2025 at 14:38):
My experience with figuring out what is faster using linters is that it is hard to avoid "caching": linters will usually re-elaborate some syntax that has already been elaborated and, in the process, will have access to cached computations. This makes speed tests performed by linters somewhat unreliable.
Bolton Bailey (Mar 10 2025 at 15:36):
Michael Rothgang said:
As a start, the pair
(continuity, fun_prop)
and(measurability, fun_prop)
could be a start.
Seems like something tryAtEachStep could be helpful with.
Michael Rothgang (Mar 10 2025 at 17:23):
Damiano Testa said:
My experience with figuring out what is faster using linters is that it is hard to avoid "caching": linters will usually re-elaborate some syntax that has already been elaborated and, in the process, will have access to cached computations. This makes speed tests performed by linters somewhat unreliable.
Good point! In the case of fun_prop and continuity, in my experience the former is ~always a lot faster, so I don't need any speed comparisons. Telling me which ones can be replaced should suffice. :-)
Violeta Hernández (Mar 19 2025 at 10:33):
A pair I've encountered a few times is (aesop, simp_all)
.
Tristan Figueroa-Reid (Mar 20 2025 at 06:13):
Michael Rothgang said:
More specifically, I'm thinking of a syntax linter which does the following, for every pair
(slower_tactic, faster_tactic)
.
- look for occurrences of the
slower_tactic
tactic
- careful: do ignore default parameters
- occurrences inside proofs (of theorems, instances or definitions) should be fine
- try to replace this by the
faster_tactic
tactic- elaborate the result: if there are no errors, print a message about the replacement. Otherwise, do nothing.
Since I imagine that this would be very slow like tryAtEachStep
, it might be a good idea to categorize these slow linters in such a way that one could manually run them for a specific file/theorem: one could use this to golf-lint only files changed in a PR, for example. (This could also contain linters regarding simp - for example, permuting simp only
calls with multiple theorems to see if there exists a potential call to simp_rw
)
(note: I just noticed that this was mentioned about 10 messages ago - since this is being brought up more often, though, it might be a good time to consider implementing such a system.)
Tristan Figueroa-Reid (Mar 21 2025 at 00:19):
Also (taking advantage of the slowness of this linter) it would be nice if that tactic was transitive - e.g. cases when simp_all
can just be simp
.
Last updated: May 02 2025 at 03:31 UTC