I was following the advice on Haskell's Wiki page: Performance/Data types to improve the performance of my code, but when I changed
data Color = Yellow | Red | Green | Blue | Empty deriving (Show, Eq)
to
newtype Color = Color Int deriving (Eq,Ord,Enum)
(yellow:red:green:blue:empty:_) = [Color 1 ..]
as suggested in the article, GHC says:
Can't make a derived instance of `Enum Color':
`Color' must be an enumeration type
(an enumeration consists of one or more nullary, non-GADT constructors)
Try -XGeneralizedNewtypeDeriving for GHC's newtype-deriving extension
In the newtype declaration for `Color'
I haven't worked with Enums much, how do I turn Color into an Enum type? Do I have to implement all the functions it defines? I thought they were all implemented when you derived that class.
Sometimes GHC's advice is bad, but in this case it's spot on. At the top of your file, put
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
GeneralizedNewtypeDeriving
is a language extension that allows you to specify that some classes should be "forwarded" to their representation's instances. That is, newtype Color = Color Int deriving (Enum)
says to implement Color
's Enum
instance just by using Int
's (after some necessary wrapping/unwrapping, which GHC generates for you).
But if this is the only reason you need Enum
, you could also omit it and just do
(yellow:red:green:blue:empty:_) = map Color [1..]
Note that by deriving Enum
you'll get only a partially correct implementation. For example, enumFrom yellow
will return a list equivalent to map Color $ [1..]
, which is probably not what you want.
So I'd rather suggest to implement Enum
together with Bounded
manually so that it satisfies rules given in the documentation of Enum
.
I suppose all this stuff could be generated automatically with Template Haskell. This would make an interesting library.
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