In short:
deriving
automatically implements functions for a few of Haskell's typeclasses such as Show
and Eq
. This cannot be done with arbitrary typeclasses, but the ones for which deriving
does work for are simple enough for automatic implementation.
The Show
typeclass defines functions for how to represent data types as a String
.
More extensively:
Are you familiar with typeclasses?
https://www.haskell.org/tutorial/classes.html
Typeclasses are similar to interfaces in Java: they define a few functions that any data type who wants to use those functions can implement.
For instance, say we have a class like such:
class Comparable a where
lessThan :: a -> a -> Bool
equalsTo :: a -> a -> Bool
Beware of the word class
. It means typeclass in the Haskell setting, not a typical "class" you would hear about in object oriented languages. The a
here is a filler type, similar to how you would expect templates would work in C++ and generics to behave in Java.
Let's say we define a data type as follows:
data Color = Red | Green | Blue
To make Comparable
work with Color
, we implement an instance
of Comparable
:
instance Comparable Color where
lessThan Red Green = True
lessThan Red Blue = True
lessThan Green Blue = True
lessThan _ _ = False
equalsTo Red Red = True
equalsTo Green Green = True
equalsTo Blue Blue = True
equalsTo _ _ = False
Roughly speaking, this now allows you to "compare" Red
, Green
, and Blue
with each other. But was there any way that GHC could have automagically guessed that this is was the exact "order" you wanted?
Taking a step back, the typeclass Show
has a similar structure:
https://hackage.haskell.org/package/base-4.9.1.0/docs/src/GHC.Show.html#Show
class Show a where
showsPrec :: Int -> a -> ShowS
show :: a -> String
showList :: [a] -> ShowS
showsPrec _ x s = show x ++ s
show x = shows x ""
showList ls s = showList__ shows ls s
Something to notice is that functions within a typeclass may be defined in terms of each other. Indeed, we could have also easily done:
class Comparable a where
lessThan :: a -> a -> Bool
equalsTo :: a -> a -> Bool
greaterThan :: a -> a -> Bool
greaterThan lhs rhs = not (lessThan lhs rhs && equalsTo lhs rhs)
However, the key point is this: for arbitrary user-defined typeclasses, GHC has no idea how their functions should be implemented when you try to associate the typeclass with a data type such as Color
or BaseballPlayer
. For some typeclasses such as Show
, Eq
, Ord
, etc, where the functionality is simple enough, GHC can generate default implementations that you can of course overwrite yourself.
Indeed, let's experiment by trying to compile the following:
data Color = Red | Green | Blue deriving (Comparable)
The result I get is this:
test.hs:9:43:
Can't make a derived instance of ‘Comparable Color’:
‘Comparable’ is not a derivable class
Try enabling DeriveAnyClass
In the data declaration for ‘Color’
Of course, some GHC extensions can be used to extend the power of deriving
, but that's for another day :)
-ddump-deriv
to GHC. This will print the code generated by allderiving
clauses. That is all it does - generates some boilerplate for you. – Dacey