Zulip Chat Archive
Stream: general
Topic: Anti-patterns in Lean
Daniel Weber (Aug 28 2024 at 04:32):
What are some examples of anti-patterns is Lean?
One example I can think of is using equality of types
Jireh Loreaux (Aug 28 2024 at 05:20):
- defeq abuse (this is likely what you meant by "using equality of types"). That is, given a type
X : Type
, create a new typedef Y : Type := X
. Then prove theorems about elements ofY
by allowing Lean to "see through" the definitional equality and using a theorem about terms of typeX
. - Using subtypes of subtypes. It's almost always a bad idea to start with a type
X
, some predicatep : X → Prop
, create the subtypeY := { x // p x }
, then take a predicateq : Y → Prop
and create a subtypeZ := { y // q y }
. It's almost certainly better to use a predicateq' : X → Prop
such that∀ x, q' x ↔ ∃ hx : p x, q ⟨x, hx⟩
and create the subtypeZ' := { x // q' x}
instead. - Sets of sets. This is related to the previous one, but it is rarely the case that you actually want to consider
s : Set X
andt : Set ↥s
; although it does happen occasionally. One of the issues is that if you haves s' : Set X
withh : s = s'
buth
is notrfl
(i.e., propeq but not defeq), then it's relatively hard to talk meaningfully about the equality oft : Set ↥s
andt' : Set ↥s'
and have it do anything useful for you. (Of course, you can say thatSubtype.val '' t = Subtype.val '' t'
, but this probably doesn't buy you much. - Over-typing. This comes up a lot when you try to do things "precisely" or avoid junk values. For instance, we have docs#divp, but it is used relatively rarely compared to the usual
/
. I would argue that's because docs#divp is over-typed (i.e., too much information is required at the time the function is used); of course, there are always a few instances where this level of type safety is actually a good thing, but most of the time it isn't. The solution is often to embrace junk values, and use hypotheses in theorems to specify an input isn't junk. Another example could be the (over-typed) definition ofVector
as an inductive definition, versus docs#Mathlib.Vector which is just a subtype of docs#List. Of course, there is a balance that needs to be struck here. - Not utilizing forgetful inheritance when designing class hierarchies. I'll just point to #mil for the explanation here. It's often easier at first to avoid forgetful inheritance, but it bites you later.
- More generally, failing to make instances canonical, thereby ending up with non-defeq (or worse, non-propeq) diamonds. Again, it's natural to just declare an instance whenever you want it, but without careful thought you end up in this situation.
- marking lemmas as
simp
because they are "obvious". This might be bad for a whole host of reasons (they have side conditions, they point in the wrong direction, they don't help reduce to a "normal form" even informally).
Daniel Weber (Aug 28 2024 at 05:24):
By equality of types I meant using HEq and cast
Damiano Testa (Aug 28 2024 at 06:58):
There was also a similar thread with more suggestions.
Last updated: May 02 2025 at 03:31 UTC