Derived Instances for Types in Haskell
02 Jan 2013Introduction
When constructing your own types in Haskell, you can make your type support a particular behavior by making it an instance of the behavioral type class required. I’ll walk through each of these derivable behaviours and how they can help.
Eq
Eq
gives your type a sense of equality amongst values of the same type. It allows you to use the ==
operator as it was intended, returning you a boolean.
From now on, ==
will do a comparison on the contents of the three strings in the Employee record for us.
Show
In my personal experience when defining types, I would be out of my mind not to make them derive Show
. Show
allows a value of your type to be put into string format - very useful for debug situations.
Just for the printing value, you can see how Show
is worth its weight in gold.
Read
Read
provides the reverse-service of what Show
does. You’ll be able to take a type in its serialized format and re-construct a type from it. Again, rather useful in debug situations.
I’ve also used this to do user-input rather cheaply. Probably not quite a “production solution” though having your users enter type data directly.
Ord
Ord
gives your value order. Once you apply Ord
you can sort or use operators like >
, <
, >=
, <=
.
Quite useful for when you need to do these sorts of comparisons.
Bounded
Bounded
will give your type a sense of the lowest and highest values achievable. You’ll be able to ask questions of the type to see what these corresponding values are.
Enum
Enum
will give your type a sense of the predecessor and successor values. This is most important when dealing with ranges in using your type. Take a look at the following deck assembly. Without Bounded
the list comprehensions would not be possible and this code would be a lot more verbose.
That’s derived instances for you anyway. They’re a great help when constructing your own types in Haskell. I think an important follow up to this blog post is being able to use these classes in conjunction with the instance keyword so that we can supply the implementation to the definition. Using the card example, we could supply an Eq
and Show
instance as follows.
You can see here that it’s quite counter-productive to supply our own Eq
implementation, but if we did have some funky rules on how we wanted equality operators to work it would be worth it. In the show implementation, I’ve tried to make the suits read a little more humanly. Around the card table, you would normally hear someone say “Do you have a 2 of clubs?” rather than “Do you have a 2 of club?”. The trailing “s” has been added in the show implementation. Neat.
Functor
Functor
is applied to wrapper types. You’ll commonly see examples used with Maybe
. You’ll use Functor
when ever you need to supply an fmap implementation. Here is a simple example that creates a wrapper data type.
Functor
is useful for types that contain something, Lists, Maps, etc.