Typeclass constraints on data declarations

I haven’t personally come across a desire to constrain the types within data types I’ve created, but it’s not obvious to me why the language designers “decided it was a bad idea to allow”. Why is that?

Because it was misleading and worked completely backwards from what would actually be useful.

In particular, it didn’t actually constrain the types within the data type in the way you’re probably expecting. What it did do was put a class constraint on the data constructor itself, which meant that you needed to satisfy the instance when constructing a value… but that was all.

So, for instance, you couldn’t simply define a binary search tree with an Ord constraint and then know that any tree has sortable elements; the lookup and insert functions would still need an Ord constraint themselves. All you’d prevent would be constructing an empty tree that “contains” values of some non-ordered type. As far as pattern matching was concerned, there was no constraint on the contained type at all.

On the other hand, the people working on Haskell didn’t think that the sensible version (that people tended to assume data type contexts provided) was a bad idea at all! In fact, class constraints on a data type declared with GADT syntax (generalized algebraic data types, enabled in GHC with the GADTs language pragma) do work in the obvious way–you need a constraint to construct the value, and the instance in question also gets stored in the GADT, so that you don’t need a constraint to work with values, and pattern matching on the GADT constructor lets you use the instance it captured.

Leave a Comment