Haskell way to go about enums - haskell

I want to represent a type of the following form :
(Card, Suit)
to represent cards in a card game where Card instances would be in the set:
{2, 3, 4, 5, 6, 7, 8, 9, J, Q, K, 1}
and Suit would have instances in the set:
{S, D, H, C}
I'd handle that with two Data declarations if that wasn't for the numbers:
data Suit = S | D | H | C deri...
but obviously adding numbers to those null arity types will fail.
So my question is, how to simulate the kind of enum you find in C?
I guess I'm misundestanding a basic point of the type system and help will be appreciated!
EDIT: I'll add some context: I want to represent the data contained in this Euler problem, as you can check, the data is represented in the form of 1S for an ace of spade, 2D for a 2 of diamond, etc...
What I'd really like is to be able to perform a read operation directly on the string to obtain the corresponding object.

I actually happen to have an implementation handy from when I was developing a poker bot. It's not particularly sophisticated, but it does work.
First, the relevant types. Ranks and suits are enumerations, while cards are the obvious compound type (with a custom Show instance)
import Text.ParserCombinators.Parsec
data Suit = Clubs | Diamonds | Hearts | Spades deriving (Eq,Ord,Enum,Show)
data Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace deriving (Eq,Ord,Enum,Show)
data Card = Card { rank :: Rank
, suit :: Suit } deriving (Eq,Ord,Bounded)
instance Show Card where
show (Card rank suit) = show rank ++ " of " ++ show suit
Then we have the parsing code, which uses Parsec. You could develop this to be much more sophisticated, to return better error messages, etc.
Note that, as Matvey said in the comments, the problem of parsing strings into their representations in the program is (or rather should be) orthogonal to how the enums are represented. Here I've cheated and broken the orthogonality: if you wanted to re-order the ranks (e.g. to have Ace rank below Two) then you would break the parsing code, because the parser depends on the internal representation of Two being 0, Three being 1 etc..
A better approach would be to spell out all of the ranks in parseRank explicitly (which is what I do in the original code). I wrote it like this to (a) save some space, (b) illustrate how it's possible in principle to parse a number into a rank, and (c) give you an example of bad practice explicitly spelled out, so you can avoid it in the future.
parseSuit :: Parser Suit
parseSuit = do s <- oneOf "SDCH"
return $ case s of
'S' -> Spades
'D' -> Diamonds
'H' -> Hearts
'C' -> Clubs
parseRank :: Parser Rank
parseRank = do r <- oneOf "23456789TJQKA"
return $ case r of
'T' -> Ten
'J' -> Jack
'Q' -> Queen
'K' -> King
'A' -> Ace
n -> toEnum (read [n] - 2)
parseCard :: Parser Card
parseCard = do r <- parseRank
s <- parseSuit
return $ Card { rank = r, suit = s }
readCard :: String -> Either ParseError Card
readCard str = parse parseCard "" str
And here it is in action:
*Cards> readCard "2C"
Right Two of Clubs
*Cards> readCard "JH"
Right Jack of Hearts
*Cards> readCard "AS"
Right Ace of Spades
Edit:
#yatima2975 mentioned in the comments that you might be able to have some fun playing with OverloadedStrings. I haven't been able to get it to do much that's useful, but it seems promising. First you need to enable the language option by putting {-# LANGUAGE OverloadedStrings #-} at the top of your file, and include the line import GHC.Exts ( IsString(..) ) to import the relevant typeclass. Then you can make a Card into a string literal:
instance IsString Card where
fromString str = case readCard str of Right c -> c
This allows you to pattern-match on the string representation of your card, rather than having to write out the types explicitly:
isAce :: Card -> Bool
isAce "AH" = True
isAce "AC" = True
isAce "AD" = True
isAce "AS" = True
isAce _ = False
You can also use the string literals as input to functions:
printAces = do
let cards = ["2H", "JH", "AH"]
mapM_ (\x -> putStrLn $ show x ++ ": " ++ show (isAce x)) cards
And here it is in action:
*Cards> printAces
Two of Hearts: False
Jack of Hearts: False
Ace of Hearts: True

data Card = Two | Three | Four | Five | Six
| Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
deriving Enum
Implementing the Enum typeclass means you can use fromEnum and toEnum to convert between Card and Int.
However, if it's important to you that fromEnum Two is 2, you will have to implement the Enum instance for Card by hand. (The autoderived instance starts at 0, just like C, but there's no way of overriding that without doing it all yourself.)
n.b. You might not need Enum --- if all you want is to use operators like < and == with your Cards, then you need to use deriving Ord.
Edit:
You cannot use read to turn a String of the form "2S" or "QH" into a (Card, Suit) because read will expect the string to look like "(a,b)" (e.g. "(2,S)" in the form you initially asked for, or "(Two,S)" in the form I suggested above).
You will have to write a function to parse the string yourself. You could use a parser (e.g. Parsec or Attoparsec), but in this case it should be simple enough to write by hand.
e.g.
{-# LANGUAGE TupleSections #-}
parseSuit :: String -> Maybe Suit
parseSuit "S" = Just S
...
parseSuit _ = Nothing
parseCard :: String -> Maybe (Card, Suit)
parseCard ('2' : s) = fmap (Two,) (parseSuit s)
...
parseCard _ = Nothing

I’d just prefix the numbers with a letter, or better yet, a word. I’d also not use too many one-letter abbreviations – H, K etc. are downright unreadable.
data Suit = Club | Spade | Heart | Diamond
data Card = Card1 | Card2 | … | Jack | Queen | King | Ace
… But I even prefer dave’s suggestion of using the number words (One, Two) for values instead.

Related

Haskell instance function

I'm solving some exercises from a book and now I'm having some difficulties:
In this exercise I shall implement Card as an instance of the class Ord.
But I don't know how exactly I could implement it, so I would appreciate any help.
My code so far looks like this:
data Suit = Diamond | Club | Spade | Heart
data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace
data Card = Card Suit Rank
instance Ord Card where
....
Now I don't know how exactly to implement this and I would very much like to understand it.
Thanks in advance for the explanations.
We can ask GHCi for information about Ord.
:info Ord
This shows the class definition, followed by a list of instances.
type Ord :: * -> Constraint
class Eq a => Ord a where
compare :: a -> a -> Ordering
(<) :: a -> a -> Bool
(<=) :: a -> a -> Bool
(>) :: a -> a -> Bool
(>=) :: a -> a -> Bool
max :: a -> a -> a
min :: a -> a -> a
{-# MINIMAL compare | (<=) #-}
-- Defined in ‘GHC.Classes’
Its superclass is Eq, and :info Eq tells us:
type Eq :: * -> Constraint
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
{-# MINIMAL (==) | (/=) #-}
-- Defined in ‘GHC.Classes’
So in order to implement Ord for Card, we need two things:
An instance Ord Card, with a definition of compare or (<=)
An instance Eq Card with a definition of (==) or (/=)
Since these instances are very mechanical to write, normally we ask the compiler to derive them automatically:
data Suit = Diamond | Heart | Spade | Club
deriving (Eq, Ord)
data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace
deriving (Eq, Ord)
data Card = Card Suit Rank
deriving (Eq, Ord)
If you pass the -ddump-deriv flag to GHC, or use :set -ddump-deriv in GHCi, it will print out the code that it generates for these instances.
However, the task is to understand how to implement these instances by hand, so let’s go through it step by step.
We’ll start with Eq. For Suit and Rank, we need to specify that each constructor is equal to itself (a.k.a. reflexivity) and all other constructors are unequal.
instance Eq Suit where
Diamond == Diamond = True
Heart == Heart = True
Spade == Spade = True
Club == Club = True
_ == _ = False
instance Eq Rank where
Seven == Seven = True
Eight == Eight = True
Nine == Nine = True
Ten == Ten = True
Jack == Jack = True
Queen == Queen = True
King == King = True
Ace == Ace = True
_ == _ = False
With that out of the way, we can define == for Card in a similar way, by pattern-matching on values of the form Card suit rank.
instance Eq Card where
-- Two cards are equal if…
Card suit1 rank1 == Card suit2 rank2
-- …their suits are equal,
-- and their ranks are equal.
= …
There are two conventional ways to define the body. One is spelling it out literally: suit1 == suit2 && rank1 == rank2. Another is to use tuples: (suit1, rank1) == (suit2, rank2).
Again, to define Ord, we can begin with the instances for the enumerations Suit and Rank. We have two choices of how to specify these: (<=) or compare. The direct option is to just list out the table of possible cases, abbreviating cases where we can:
instance Ord Suit where
Diamond <= _ = True
Heart <= Diamond = False
Heart <= _ = True
Spade <= Diamond = False
Spade <= Heart = False
Spade <= _ = True
Club <= Club = True
Club <= _ = False
instance Ord Rank where
…
For Card, we now just need to follow the same basic form as for Eq. Since we defined (<=) for Suit and Rank, note that we automatically get a default implementation of the other comparison functions like compare and (<) for those types.
instance Ord Card where
-- Two cards are in order if…
Card suit1 rank1 <= Card suit2 rank2
-- …one rank is less than the other,
-- or their ranks are equal and suits are in order.
= …
Again you can translate this comment verbatim using (<), (||), (==), (&&), (<=).
Try implementing these instances based on compare instead of (<=). Hint: use comparing and instance Monoid Ordering from Data.Ord.
Add deriving (Enum) to Rank and Suit—try using fromEnum to simplify their Eq and Ord definitions.
I can't imagine the exercise actually wanted you to manually write the necessary instances. Especially for Suit and Rank, they would be very tedious (and error prone) to write.
Instead, you probably want to use the deriving keyword to automatically derive the necessary instances. If you write:
data Suit = Diamond | Heart | Spade | Club
deriving (Eq, Ord)
this automatically derives Eq and Ord instances. (The Eq instance is required by the Ord instance.) The derived Eq instance is self-explanatory, and the derived Ord instance uses the order in which the constructors appear in the declaration, so Diamond is the smallest and Club is the biggest. If you want bridge order, use:
data Suit = Club | Diamond | Heart | Spade
deriving (Eq, Ord)
instead. Similarly,
data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace
deriving (Eq, Ord)
orders the rank from Seven (smallest) to Ace (largest). Then, if you write:
data Card = Card Rank Suit
deriving (Eq, Ord)
the derived instance sorts Cards according to the first field Rank, with ties broken by Suit. If you wrote:
data Card = Card Suit Rank
deriving (Eq, Ord)
it would instead order them by Suit, then Rank.
Some code to illustrate:
data Suit = Diamond | Heart | Spade | Club
deriving (Eq, Ord)
data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace
deriving (Eq, Ord)
data Card = Card Rank Suit
deriving (Eq, Ord)
main = do
let heart8 = Card Eight Heart
spade8 = Card Eight Spade
diamond7 = Card Seven Diamond
print $ heart8 == heart8 -- True
print $ heart8 == spade8 -- False
print $ heart8 < spade8 -- True
print $ diamond7 < spade8 -- True

How to write the instance for Show of a given datatype shorter?

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
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!
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
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

How do you sort a list of tuple by one of the tuple-Haskell

I have a list of cards and want to sort list of cards([Card]) by suit but the way Card is defined makes it confusing to navigate. Can someone help me define a simple function to sort the list.
Tried things like :
sortHand ::[Card]-> [Card]
sortHand hand = sort hand
but I can't figure out how to filter the suit only
Card is defined:
data Suit = Spade | Club | Diamond | Heart
deriving (Eq, Ord, Enum, Bounded)
data Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
deriving (Eq, Ord, Enum, Bounded)
data Card = Card Suit Rank
deriving (Eq)
This is what the sortBy :: (a -> a -> Ordering) -> [a] -> [a] and comparing :: Ord b => (a -> b) -> (b -> b -> Ordering) functions are for. The first lets you sort by a custom ordering, the other lets you define an ordering by mapping a's to some b which has an ordering (a card to a suit in this example).
You could use these together to define
sortBySuit hand = sortBy (comparing $ \(Card suit _) -> suit) hand
Note however due to how the automatically derived Ord instances work your Card type would already be ordered by suit first and then rank if you just added a deriving Ord to your data definition.
This is easy if you make Card a record type:
data Card = Card { cardSuit::Suit, cardRank::Rank }
deriving (Eq)
*Main> :m +Data.List
*Main Data.List> :m +Data.Ord
*Main Data.List Data.Ord> sortBy (comparing cardSuit) [Card Club Three, Card Diamond Two, Card Spade Eight, Card Spade Five]
[Card {cardSuit = Spade, cardRank = Eight},Card {cardSuit = Spade, cardRank = Five},Card {cardSuit = Club, cardRank = Three},Card {cardSuit = Diamond, cardRank = Two}]

How to create data out of two other data?

I am trying to make a Card data type. The problem I am having is that I currently have the cards set up as a "CardValue" and a "Suit" data type which are each separate, and then I was trying to make a "Card" data type that is essentially just (CardValue, Suit). I need the "Card" data to be data and not type so that I can make it an instance of show, but I do not know if this is possible the way I am doing this. Is there a way to make a single Card data that would have every possible card in a deck without going "data Card = AceHeart | AceSpade | AceClub ... etc."?
Here is what I have so far:
data CardValue = Ace | Two | Three
| Four | Five | Six
| Seven | Eight | Nine
| Ten | Jack | Queen
| King deriving (Bounded, Enum, Show, Eq, Ord)
data Suit = Clubs | Spades | Hearts | Diamonds deriving (Show, Eq)
data Card = (CardValue, Suit)
instance Show Card where
show (v, s) = show v ++ " of " ++ show s
Yes, you just got the syntax slightly wrong.
Just write
data Card = Card CardValue Suit
instead (note that the second "Card" in the above code could also be called something else; The left side names the type, the right side is a name for values of type card), and then you can write your show instance as
instance Show Card where
show (Card v s) = show v ++ " of " ++ show s
Since you use data you define a new data type. You thus will need to specify a data constructor. You can not use the tuple data constructor (,) here.
You thus can define:
data Card = Card CardValue Suit
Then you can for example implement an instance of Show:
instance Show Card where
show (Card v s) = show v ++ " of " ++ show s
That being said, Show is usually supposed to generate output that is Haskell code (so you can for example inject it back in the interpreter).
It might be better to define a class:
class Representable a where
repr :: a -> String
and thus implement this for Card as:
instance Representable Card where
repr (Card v s) = show v ++ " of " ++ show s

How to implement custom ordering for data types in Haskell?

Let's say I have a data type that represents a deck of poker cards like so
data Suit = Clubs | Spades | Hearts | Diamonds deriving (Eq)
instance Show Suit where
show Diamonds = "♦"
show Hearts = "♥"
show Spades = "♠"
show Clubs = "♣"
data Value = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace deriving (Eq, Ord)
data Card = Card {
value :: Value
, suit :: Suit
} deriving (Eq, Ord)
instance Show Card where
show (Card v s) = show s ++ show v
Haskell helps me already a lot by allow me to derive Eq and Ord without explicitly specifying those relations.
This is especially useful, because I want to use Ord to ultimately compare the value of two hands according to Poker rules.
Now in Poker, the suits do not really matter in terms of ordering. Therefore I tried
instance Ord Suit where
compare Clubs Spades = EQ
compare Clubs Hearts = EQ
compare Clubs Diamonds = EQ
compare Spades Hearts = EQ
compare Spades Diamonds = EQ
compare Hearts Diamonds = EQ
This is already a bit verbose ... and it does not even work:
*P054> a
♠A
*P054> b
♣A
*P054> a < b
*** Exception: P054.hs:(12,9)-(17,36): Non-exhaustive patterns in function compare
So how can I properly define an ordering on Suit that expresses the fact that all suits are equal?
You are missing several combinations, e.g. all with Clubs on the right hand side. If all are equal, what are the possible results of compare, regardless of the input? There is only one: EQ. Therefore we don't even need to look at a or b:
instance Ord Suit where
compare _ _ = EQ
However, that Ord instance is rather useless. Alternatively you can create a custom instance for Card,
instance Ord Card where
compare a b = compare (value a) (value b)
-- compare = compare `on` value -- using `on` from Data.Function
-- compare = comparing value -- using `comparing` from Data.Ord

Resources