As many as you can get your hands on
Some clear trends have evolved with the development of Haskell since the early days.
Warnings have gradually been taken more and more seriously. To start with they were used relatively sparingly with individual warnings being enabled as needed. Gradually we have arrived at the stage where folks tend to enable them all, and then some, and supplement them with use tools like hlint. It is standard practice to use
-Werrorto prevent any code from being checked in showing warnings. Critical to this is the ability turn off a warning locally if it is known to be harmless.
Constructions like default clauses in case statements that can hide warnings are avoided unless necessary (so analysis of enumerations tend to be spelt out with a case for each enumeration).
newtypewrappers are being used to distinguish integral and text types, and anything else that needs distinguishing.
Partial functions are avoided except in very limited scenarios where it is possibly to prove that the functions are being applied to values in their domain.
Regression testing is now taken seriously.
The last point gives a strong hint as to what has been happening. As Haskell has been used in production settings it has acquired those norms. But with this we have seen a natural tendency to wring as much as possible out of static analysis.
This is a reminder that static analysis, far from being an academic preoccupation, is now a key tool in managing code bases at scale.
I would recommend that anyone coming to Haskell cultivate the habit of enabling as many warnings and the potential for type errors as possible. I know that when the penny dropped with me writing code became way more satisfying — and stable.
Got an issue with any of this? Please share or drop me a line (see below).