The definition of deriving on stack overflow is:
"In Haskell, a derived instance is an instance declaration that is generated automatically in conjunction with a data or newtype declaration. The body of a derived instance declaration is derived syntactically from the definition of the associated type."
I don't really understand any of it to be honest.
The code below is taken from: Link
data BaseballPlayer = Pitcher
| Catcher
| Infielder
| Outfielder
deriving Show
barryBonds :: BaseballPlayer -> Bool
barryBonds Outfielder = True
barryInOf = print(barryBonds Outfielder)
My question is, what does the deriving-statement do in this specific case, and also what does the deriving-statement do in general?.
What's a typeclass in Haskell? A typeclass defines a set of methods that is shared across multiple types. For a type to belong to a typeclass, it needs to implement the methods of that typeclass. These implementations are ad-hoc: methods can have different implementations for different types.
The Eq typeclass provides an interface for testing for equality. Any type where it makes sense to test for equality between two values of that type should be a member of the Eq class. All standard Haskell types except for IO (the type for dealing with input and output) and functions are a part of the Eq typeclass.
The shows functions return a function that prepends the output String to an existing String . This allows constant-time concatenation of results using function composition.
An instance of a class is an individual object which belongs to that class. In Haskell, the class system is (roughly speaking) a way to group similar types. (This is the reason we call them "type classes"). An instance of a class is an individual type which belongs to that class.
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 :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With