Let’s think about horses. There are three kinds of Horse:
data Horse = SmallHorse | LargeHorse | OtherHorse
Let’s make a function to check whether two Horses are in fact equivalently sized.
isSameHorse :: Horse -> Horse -> Bool
= first == second isSameHorse first second
Looks like a classic. Let’s run it!
SmallHorse LargeHorse isSameHorse
Shit!
No instance for (Eq Horse) arising from a use of ‘==’
• In the expression: first == second
• In an equation for ‘isSameHorse’:
= first == second isSameHorse first second
That’s terrible news. What’s wrong here? Apparently, we need to make an instance of the Eq
(short for ‘equality’) typeclass for Horse
before they can be compared. What’s the Eq
typeclass?
We can find out more by firing up ghci
, the GHC repl.
You should see a prompt with the following:
Prelude>
If we enter :info Eq
, we get the following:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
{-# MINIMAL (==) | (/=) #-}
It shows there are two functions in the Eq
typeclass, ==
and /=
(equals and not-equals), and that a “minimal” definition of Eq
only needs one of those.
Let’s start again and make a better horse.
data BetterHorse = Tiny | Average | Huge
Let’s not make the same mistake this time - let’s make an instance of the Eq
typeclass for them. We are going to implement ==
which has a type of a -> a -> Bool
.
instance Eq BetterHorse where
Tiny == Tiny = True
Average == Average = True
Huge == Huge = True
== _ = False _
OK, seems fine. We’ve listed all the times two BetterHorse
are the same and used _ == _ = False
to mean “anything else is not equal” to save ourselves listing every alternative.
isSameBetterHorse :: BetterHorse -> BetterHorse -> Bool
= first == second isSameBetterHorse first second
Now our BetterHorse
comparing function works. Let’s give it a go.
nope :: Bool
= isSameBetterHorse Tiny Huge
nope -- nope = False
yep :: Bool
= isSameBetterHorse Average Average
yep -- yep = True
All seems to be fine here. We even get the /=
function for free by defining ==
.
nice :: Bool
= Average /= Tiny
nice -- nice = True
If you’re thinking “this seems laborious”, you’d be right. Fortunately, for basic data types like this, we can simply auto-generate an Eq
instance in the data definition like this:
data LazyHorse = LazyTiny | LazyOther deriving (Eq)
= LazyTiny == LazyTiny
workingNow -- workingNow == True
Great!
Make sense? If not, why not get in touch?
Further reading: