I am just beginning to learn Haskell. I have seen many intro examples explaining the basics of types, but they often have a deriving
statement below the type. Here is an example from Chapter 3 of RealWorldHaskell:
data Cartesian2D = Cartesian2D Double Double
deriving (Eq, Show)
data Polar2D = Polar2D Double Double
deriving (Eq, Show)
They explain deriving somewhat in Chapter 6, which helps you know how it is used.
So far from what I understand, deriving (Show)
is necessary to tell Haskell how to turn your type into a string. That makes sense at a practical level. I come from JavaScript land, so to me you could easily imagine this would be implemented like:
Polar2D.prototype.toString = function(){
return '[Polar2D]';
};
In Haskell, they give the example of how to implement your own Show
for the Color
type, instead of using deriving
.
data Color = Red | Green | Blue
instance Show Color where
Red = "red"
Green = "green"
Blue = "blue"
That means when your in the ghci
repl, you can do:
> show Red
"red"
But this doesn't explain what deriving
is actually doing, it's still magic to me.
My question is, what is happening under the hood with deriving
? Also, is there a place on GitHub in the Haskell source where you can see the implementation? That may also be helpful.
Deriving means that your data type is automatically able to "derive" instances for certain type classes. In this case BaseballPlayer derives Show which means we can use any function that requires an instance of Show to work with BaseballPlayer .
The Eq class defines equality ( == ) and inequality ( /= ). All the basic datatypes exported by the Prelude are instances of Eq , and Eq may be derived for any datatype whose constituents are also instances of Eq . The Haskell Report defines no laws for Eq .
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.
GHC is effectively just writing the same instance you wrote by hand, if you pass -ddump-deriv
to the compiler you can see the code it generates. For instance:
Prelude> data Color = Red | Green | Blue deriving (Show)
==================== Derived instances ====================
Derived instances:
instance Show Color where
showsPrec _ Red = showString "Red"
showsPrec _ Green = showString "Green"
showsPrec _ Blue = showString "Blue"
showList = showList__ (showsPrec 0)
Generic representation:
Generated datatypes for meta-information:
Representation types:
There's not really much magic going on here, Show
just has a very mechanical implementation. Inside it looks at the internal form of the data constructors (the type is DataConRep
in GHC's source ) which it gets from translating the frontend AST and then looks at the names provided in the frontend source and adds a new Show instance in terms of these names and any nested types that also implement Show. The new auto-generated typeclass is registered just like a hand-coded class as if it were written in the current module.
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