Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

list data type haskell with bounds

I have the following type definitions to represent cards:

data Suit = Hearts | Spades | Diamonds | Clubs
data Rank = Numeric Integer | Jack | Queen | King | Ace
data Card = Card Rank Suit
data Deck = None | Cons Card Deck

Numeric Integer represents ranks from 2 to 10.

Now I want to write a function to get the full deck:

fullDeck :: Deck

How could I generate the full deck in the most elegant way? I understand that some of these definitions are ugly but I have no freedom to choose this.

Thanks

like image 270
Yauhen Yakimenka Avatar asked Dec 01 '22 18:12

Yauhen Yakimenka


2 Answers

Does something like

-- Not sure why you're reinventing a list but
fromList :: [Card] -> Deck
fromList = foldr Cons None

fullDeck = fromList [Card r s | s <- [Hearts, Spades, Diamonds, Clubs]
                              , r <- map Numeric [2..9]++[Jack, Queen, King, Ace]]

Look nice? we're just using list comprehensions to generate a list of all possibilities than smashing it into a Deck.

like image 104
Daniel Gratzer Avatar answered Dec 19 '22 19:12

Daniel Gratzer


You could consider using the universe package. It doesn't really make the code much easier, but it's fun. =)

Here's how it would look.

import Data.Universe

data Suit = Hearts | Spades | Diamonds | Clubs deriving (Bounded, Enum)
data Rank = Numeric Integer | Jack | Queen | King | Ace

instance Universe Suit
instance Universe Rank where
    universe = map Numeric [2..10] ++ [Jack, Queen, King, Ace]

instance Finite Suit
instance Finite Rank

Now you can use universeF :: [(Rank, Suit)] as your full deck of cards. If you really want custom Card and Deck types, you can add just a few lines of code:

data Card = Card Rank Suit
instance Universe Card where
    universe = [Card rank suit | (rank, suit) <- universeF]
instance Finite Card

data Deck = None | Cons Card Deck
fullDeck = foldr Cons None universeF
like image 40
Daniel Wagner Avatar answered Dec 19 '22 17:12

Daniel Wagner