How can I reuse a class instance for a newtype?
class, haskell
Solution
There's an extension called GeneralizedNewtypeDeriving that you can use for the same end. It lets you "carry over" definitions from the underlying type to the newtype.
Here's a small, contrived code example:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Foo = Foo Integer deriving (Show, Eq, Num)\
It's a bit confusing though: standard derived classes like `Show` and `Eq` will still be derived the normal way. So `Foo`'s `Show` instance is different from `Integer`'s. However, all other classes get carried through directly, so `Foo`'s `Num` instances is the same as `Integer`'s.
You have to be a little careful with it because it does not always play well with certain Haskell extensions. However, for the simple `Num` case, it's a perfectly good option. I also believe that upcoming versions of GHC are fixing some of the common problems with `GeneralizedNewtypeDeriving`, so it should become a much safer extension in the near future.
Problem
I have defined a type called `Natural` which is an positive integer that includes 0: ``` newtype Natural = Natural Integer deriving (Eq, Ord) instance Show Natural where show (Natural i) = show i toNatural :: (Integral i) => i -> Natural toNatural x | x < 0 = error "Natural cannot be negative" | otherwise = Natural $ toInteger x fromNatural :: Natural -> Integer fromNatural (Natural i) = i instance Num Natural where fromInteger = toNatural x + y = toNatural (fromNatural x + fromNatural y) x - y = let r = fromNatural x - fromNatural y in if r < 0 then error "Subtraction yielded a negative value" else toNatural r x * y = toNatural (fromNatural x * fromNatural y) abs x = x signum x = toNatural $ signum $ fromNatural x instance Enum Natural where toEnum = toNatural . toInteger fromEnum = fromInteger . fromNatural ``` In my code it is common with `newtype`s that take a `Natural` as parameter. And since I want these types to be instances of `Num` and `Enum`, I find myself reimplementing the same classes over and over: ``` newtype NodeId = NodeId Natural deriving (Show, Eq, Ord) instance Num NodeId where fromInteger = NodeId . toNatural (NodeId x) + (NodeId y) = NodeId (x + y) (NodeId x) - (NodeId y) = NodeId (x - y) (NodeId x) * (NodeId y) = NodeId (x * y) abs (NodeId x) = NodeId (abs x) signum (NodeId x) = NodeId (signum x) instance Enum NodeId where toEnum = NodeId . toEnum fromEnum (NodeId x) = fromEnum x ... newtype InstructionId = InstructionId Natural deriving (Show, Eq) instance Num InstructionId where fromInteger = InstructionId . toNatural (InstructionId x) + (InstructionId y) = InstructionId (x + y) (InstructionId x) - (InstructionId y) = InstructionId (x - y) (InstructionId x) * (InstructionId y) = InstructionId (x * y) abs (InstructionId x) = InstructionId (abs x) signum (InstructionId x) = InstructionId (signum x) instance Enum InstructionId where toEnum = InstructionId . toEnum fromEnum (InstructionId x) = fromEnum x ... newtype PatternId = PatternId Natural deriving (Show, Eq) instance Num PatternId where fromInteger = PatternId . toNatural (PatternId x) + (PatternId y) = PatternId (x + y) (PatternId x) - (PatternId y) = PatternId (x - y) (PatternId x) * (PatternId y) = PatternId (x * y) abs (PatternId x) = PatternId (abs x) signum (PatternId x) = PatternId (signum x) instance Enum PatternId where toEnum = PatternId . toEnum fromEnum (PatternId x) = fromEnum x ``` As you see these implementations are almost identical, which made me wonder whether I could implement some class `A` that would itself implement the `Num` and `Enum` classes, and then for each `newtype` I would only need to implement some simple function (maybe not any function at all) of `A`. But I'm not sure how to do that or whether it's even possible at all. Any ideas?