
Andrew Bromage
I also think that 80% of the uses of Bool are wrong.
Any time that you see this:
doSomething :: Bool -> Stuff -> MoreStuff
Not only is it not obvious what Bool means, it's not obvious what the sense of it should be. In fact, almost every time I see an argument in a function that I haven't used for a while, I find myself reaching for the documentation, because I can never remember what it means.
[...]
In Haskell, it takes one line to declare a new enumerated type with just a few elements. For very little effort, you get a huge payoff in usability:
data Silliness = Silly | Sensible
silliness :: PossiblySillyThing -> Silliness
-- Now I don't have to remember what the first argument means or -- which way around it's supposed to be. It's obvious from the type. doSomething :: Silliness -> Stuff -> MoreStuff
I'm sorry to go through this in detail, but this stuff is easy to forget.
Unfortunately the relevant prelude functions, like not, &&, all, ..., are all written in a way that they don't work for Silliness.
Oh, and one more thing: Everything I've said about Bool goes triply for Either.
And for (,), of course. ;-) The trade-off currently is readability versus re-use of existing functions. A generic prelude, where ``not Silly'' is automagically ``Sensible'', might bring some of the best of both worlds, but could also spawn new confusion: with the definition above, we would probably get: < forall x :: Silliness . Silly && x = Silly < forall x :: Silliness . Sensible || x = x With respect to the name ``Silliness'', ``Silly'' intuitively corresponds to ``True'', but comes first, unlike ``True'' in data Bool = False | True ``Getting the names right'' is important, but hard. Wolfram