I’ve heard that there are some problems with Haskell’s “broken” constraint system, as of GHC 7.6 and below. What’s “wrong” with it? Is there a comparable existing system that overcomes those flaws?
For example, both edwardk and tekmo have run into trouble (e.g. this comment from tekmo).
Ok, I had several discussions with other people before posting here because I wanted to get this right. They all showed me that all the problems I described boil down to the lack of polymorphic constraints.
The simplest example of this problem is the
MonadPlusclass, defined as:… with the following laws:
Notice that these are the
Monoidlaws, where theMonoidclass is given by:So why do we even have the
MonadPlusclass? The reason is because Haskell forbids us from writing constraints of the form:So Haskell programmers must work around this flaw of the type system by defining a separate class to handle this particular polymorphic case.
However, this isn’t always a viable solution. For example, in my own work on the
pipeslibrary, I frequently encountered the need to pose constraints of the form:Unlike the
MonadPlussolution, I cannot afford to switch theMonadtype class to a different type class to get around the polymorphic constraint problem because then users of my library would losedonotation, which is a high price to pay.This also comes up when composing transformers, both monad transformers and the proxy transformers I include in my library. We’d like to write something like:
This first attempt doesn’t work because
liftdoes not constrain its result to be aMonad. We’d actually need:… but Haskell’s constraint system does not permit that.
This problem will grow more and more pronounced as Haskell users move on to type constructors of higher kinds. You will typically have a type class of the form:
… but you will want to constrain some lower-kinded derived type constructor:
However, without polymorphic constraints, that constraint is not legal. I’ve been the one complaining about this problem the most recently because my
pipeslibrary uses types of very high kinds, so I run into this problem constantly.There are workarounds using data types that several people have proposed to me, but I haven’t (yet) had the time to evaluate them to understand which extensions they require or which one solves my problem correctly. Somebody more familiar with this issue could perhaps provide a separate answer detailing the solution to this and why it works.