I am learning Haskell, so I'm writing some simple card games. I've defined some data types:
data Rank = Ace|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten|Jack|Queen|King deriving (Eq,Show,Ord)
data Suit = Hearts|Spades|Diamonds|Clubs deriving (Show)
data Card = Card Rank Suit
Now I'd like to create a pristine deck of 52 cards. I'm sure there is a slick way to do it, but all I can come up with is:
pristineDeck = [Card Ace Hearts, Card Two Hearts, ...]
Can I get Haskell to generate this list for me?
List comprehensions are a very tidy syntax for this. If you derive Enum
on Rank
and Suit
you can express it very simply as:
pristineDeck = [ Card rank suit | suit <- [Hearts .. Clubs], rank <- [Ace .. King] ]
If you're wondering why I have suit
and rank
in different orders, the first is because of the order the Card
constructor uses, while the latter is to get the order of the resulting list--suits together in ascending order.
In more generality, or when a single list comprehension gets too bulky, the cartesian product is exactly the behavior given by the Monad
instance for lists. The following is equivalent to the list comprehension above:
pristineDeck = do suit <- [Hearts .. Clubs]
rank <- [Ace .. King]
return $ Card rank suit
As one other minor point, to save yourself the trouble of remembering what order the Suit
values are in, deriving Bounded
as well will enable to write [minBound .. maxBound]
to enumerate all values of any type with instances of both Enum
and Bounded
.