Reputation:
Apologies in advance for a beginner question, but I have struggled to find useful info on this. I was working through "Learn You Haskell for Great Good" and am trying to understand the deriving keyword, which seems like Java's implements but supposedly with cool automatic code generation because of the category theory stuff or something. I declare a data structure for 2-vectors like
data R2 = R2 {x :: Double, y :: Double} deriving (Show)
Then I can use it for things like
show (R2 1.0 2.0)
Now what I'd like to do is vector addition and scalar multiplication, like
(2.0 * (R2 1.0 2.0)) + (R2 3.0 4.0)
but when I try
Prelude> data R2 = R2 { x :: Double, y :: Double} deriving (Num,Show)
<interactive>:3:52:
Can't make a derived instance of `Num R2':
`Num' is not a derivable class
In the data declaration for `R2'
So the compiler figured out how to show the cartesian product of primitive types, but addition is too hard? Maybe Num isn't the right type class to derive? How often can one expect to derive a type class and get working code without additional work, like how I didn't have to write my own show function?
Thanks very much,
John
Upvotes: 8
Views: 334
Reputation: 34398
trying to understand the deriving keyword, which seems like Java's implements but supposedly with cool automatic code generation
instance
is a bit more like implements
, in that you state that a type is an instance of a type class and then write the implementations. deriving
is all about the cool automatic generation of those implementations (though it does subsume instance
).
How often can one expect to derive a type class and get working code without additional work, like how I didn't have to write my own show function?
Alexey Romanov's answer covers for which classes deriving
works. There is also another way to auto-generate instances: using generics. From a bird's eye view, it works like this: you describe what an instance should look like for a generic type and then, for any type you want to have an instance, derive Generic
and add an empty (i.e. with no implementations, as they will be generated automatically) instance
declaration. Some libraries like aeson
and binary
offer generic instances ready to use, and you can of course roll your own for your classes.
Upvotes: 6
Reputation: 62848
Sadly, deriving only works for a small handful of classes, where the necessary code is hard-wired into the compiler. You can write instances yourself for any class, but only this small handful can be derived automatically.
Upvotes: 0
Reputation: 47392
Here's one reason that you can't derive the Num class
data Vector = Vector Int Int
instance Num Vector where
Vector a b + Vector c d = Vector (a + c) (b + d)
Vector a b * Vector c d = Vector (a * c) (b * d)
data Complex = Complex Int Int
instance Num Complex where
Complex a b + Complex c d = Complex (a + c) (b + d)
Complex a b * Complex c d = Complex (a * c - b * d) (a * d + b * c)
Both are sensible instances that a real programmer might want to define. For a given data definition with two Int
fields, which instance should the deriving
clause pick?
Upvotes: 5
Reputation: 11973
The Haskell Report 2010 (the document that describes the Haskell language and which all implementions should follow) defines the conditions for deriving a class C
as follows:
- C is one of
Eq
,Ord
,Enum
,Bounded
,Show
, orRead
.- There is a context
cx′
such thatcx′ ⇒ C tij
holds for each of the constituent typestij
.- If
C
isBounded
, the type must be either an enumeration (all constructors must be nullary) or have only one constructor.- If
C
isEnum
, the type must be an enumeration.- There must be no explicit instance declaration elsewhere in the program that makes
T u1 … uk
an instance ofC
.- If the data declaration has no constructors (i.e. when n = 0), then no classes are derivable.
Also, later in the report, it is said that it's also possible to derive Data.Ix
instances.
To find out how a particular instance is derived exactly (for example, what does the derived Show
instance output?), read the section about it in the report. That section only gives implementations for the cases where the above conditions are met. That's why it's impossible to derive Num
instances: it's not specified what that instance should do!
GHC also provides a few extensions that make allow for deriving more classes.
Those extensions are not part of standard Haskell, so they have to enabled explicitly. For example, if GenericNewtypeDeriving
is enabled, you can write the following:
newtype MyInt = MyInt Int deriving (Num)
-- By GenericNewtypeDeriving, GHC will just "copy" the instance
-- for the base type of the newtype, in this case, it'll use the `Num Int` instance.
You can read about these extensions in the GHC user guide
Upvotes: 4
Reputation: 170805
See https://downloads.haskell.org/~ghc/7.10.2/docs/html/users_guide/deriving.html:
In Haskell 98, the only classes that may appear in the deriving clause are the standard classes Eq, Ord, Enum, Ix, Bounded, Read, and Show.
GHC also allows deriving Generic
, Functor
, Data
, Typeable
, Foldable
and Traversable
for data
declarations, and any classes for newtype
declarations (after enabling the relevant extensions, as listed in the linked page).
Upvotes: 5