Reputation: 68
I´m quite new to Haskell but I wonder how I can write following Code shorter:
data Suite = Club | Heart | Spade | Diamond
data Value = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen |
King | Ace
data Card = Card Suite Value
instance Show Suite where
show Club = "Club"
show Heart = "Heart"
show Spade = "Spade"
show Diamond = "Diamond"
instance Enum Suite where
enumFromTo Club Diamond = [Club, Heart, Spade, Diamond]
enumFromTo Heart Diamond = [Heart, Spade, Diamond]
enumFromTo Club Spade = [Club, Heart, Spade]
instance Show Value where
show Two = "Two"
show Three = "Three"
show Four = "Four"
show Five = "Five"
show Six = "Six"
show Seven = "Seven"
show Eight = "Eight"
show Nine = "Nine"
show Ten = "Ten"
show Jack = "Jack"
show Queen = "Queen"
show King = "King"
show Ace = "Ace"
I want to write the instance for Show Value way shorter. Is there a good way to do this or do I need to write all of it? I also wonder how i could go from here if I want to define the same instances for Eq Card, Ord Card? So far
instance Eq Card where
Card _ _ == _ = False
instance Ord Card where
Card Heart Three > Card Heart Two = True
worked, but to write every single possibility would be quite a lot of work. Thanks for any answers!
Edit: I´m aware of the possiblity to append deriving (Show, etc..) but I don´t want to use it
Upvotes: 3
Views: 118
Reputation: 170899
In some cases, such as Instance Show Value
, there is no good way to shorten it without deriving
(not counting the ones in dfeuer's answer).
But in others there is! E.g.
for the Enum
instances it's enough to define fromEnum
and toEnum
, all the rest have default definitions. You certainly don't need to list all possibilities in enumFromTo
as your example code does.
After you define instance Enum Value
, you can write comparison functions by converting to Int
and comparing the results:
instance Eq Value where
x == y = fromEnum x == fromEnum y
instance Ord Value where
compare x y = compare (fromEnum x) (fromEnum y)
You can use instances for Value
and Suit
when writing definitions for Card
, e.g.
instance Eq Card where
Card s1 v1 == Card s2 v2 = s1 == s2 && v1 == v2
Upvotes: 2
Reputation: 48631
You've rejected deriving
these instances, which is the main way we avoid that much boilerplate. The most obvious remaining elementary way to shorten the Show Value
is to use a case
expression. This uses an extra line but shortens each case slightly:
instance Show Value where
show x = case x of
Two -> "Two"
Three -> "Three"
-- etc.
Expanding to non-elementary ways, you could
Use generics, either the somewhat more modern version in GHC.Generics
or (probably easier in this case) the one in Data.Data
. For these, you'll need deriving Generic
or deriving Data
, respectively, and then you can write (or dig up on Hackage) generic versions of the class methods you need. Neither of these approaches seems very appropriate for a Haskell beginner, but you can work up to them over a number of months.
Use Template Haskell. This is a very advanced language feature, and despite working with Haskell for many years, I have not really begun to grasp how to program with it. Good luck!
Upvotes: 6
Reputation: 2044
If you just want your show
method call to print the name of the constructor (as it appears here), there's no need to manually instance them at all. You can automatically derive the Show
instance thusly:
data Suit = Club | Heart | Spade | Diamond
deriving Show
data Value = Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen | King | Ace
deriving Show
Upvotes: 4