Richard A. O'Keefe wrote:
I think the practice of constraint in type definitions is generally discouraged,
Is this true? If so, why?
As a practical matter, a Haskell 98 constraint infects every place you might like to use the type. They're like prion proteins, corrupting everything they touch, replicating implacably as they go. Here's the usual pattern that leads to the abandonment of constraints on types by the previously innocent coder. You add the constraint in the one place you think you need it, only to find that the type checker insists that three more are now required on previously pristine code that otherwise never mentions your type. You reluctantly add the constraint to those, and the compiler demands another seven uses. Now your code is littered with meaningless spaghetti constraints that obfuscate your original intent. The same contagion also costs you the ability to derive instances of many useful built-in typeclasses, such as Functor. The constraint on the type requires that a function such as fmap must have the constraint, too, and thus the plague continues. Pre-GADT syntax doesn't have this problem. {-# LANGUAGE GADTs #-} data Foo a = Show a => Foo a foo :: Foo a -> a foo (Foo a) = a Notice the change in the location of the constraint, and the lack of a need for a constraint on the function foo. Real GADTs avoid the problem in a similar way. data Bar a where Bar :: Show a => a -> Bar a bar :: Bar a -> a bar (Bar a) = a