Reputation: 1601
I have a snippet of code in which I have declared two datatypes. I've auto-derived both as members of the typeclass enum
, however, I dislike that they are not "circular". By this, I mean that calling succ Sun
should yield me Mon
. succ Dec
should result in Jan
. So instead of writing my own enum I did this:
data WeekDay = Mon | Tue | Wed | Thu | Fri | Sat | Sun
deriving (Enum, Show, Eq, Bounded)
data Month = Jan | Feb | Mar | Apr | May | Jun | July | Aug | Sep | Oct | Nov
| Dec
deriving (Enum, Show, Eq, Bounded)
class Circ a where
next :: Enum a => a -> a
instance Circ WeekDay where
next a = if a == maxBound then minBound else succ a
instance Circ Month where -- this is nearly identical to the one above
next a = if a == maxBound then minBound else succ a
My question is: Is there a neater, less redundant way of writing this? In other words, I have two nearly identical instances written, with the datatype name (WeekDay vs. Month) being the only variable that changed.
Upvotes: 6
Views: 610
Reputation: 35089
I would like to build on Ingo's answer by pointing out that you don't actually need to define a type class at all. You can just define the following function without invoking any additional type class:
next :: (Eq a, Bounded a, Enum a) => a -> a
next a = if a == maxBound then minBound else succ a
Now you don't have to declare instance Circ
for all of your types.
Upvotes: 5
Reputation: 1622
You could add prev
too
class (Enum a, Bounded a, Eq a) => Circ a where
next :: a -> a
next a = if a == maxBound then minBound else succ a
prev :: a -> a
prev a = if a == minBound then maxBound else pred a
Upvotes: 2
Reputation: 36339
class (Enum a, Bounded a, Eq a) => Circ a where
next :: a -> a
next a = if a == maxBound then minBound else succ a
instance Circ WeekDay
instance Circ Month
Upvotes: 11
Reputation: 144136
It appears you can do the following if you enable the FlexibleInstances
and UndecidableInstances
extensions:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
instance (Eq a, Bounded a, Enum a) => Circ a where
next e = if e == maxBound then minBound else succ e
Upvotes: 3