list data type haskell with bounds

江枫思渺然 提交于 2019-12-10 07:27:35

问题


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


回答1:


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.




回答2:


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



回答3:


Quickly hacking around, came up with this:

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

cards :: [Card]
cards = do
  suit <- [Hearts, Spades, Diamonds, Clubs]
  rank <- Ace : (map Numeric [2..10]) ++ [Jack, Queen, King]
  return (Card rank suit)

listToDeck :: [Card] -> Deck
listToDeck [] = None
listToDeck (x:xs) = Cons x $ listToDeck xs

Is that elegant enough? :D




回答4:


@jozefg's answer is probably the easiest way, but an alternative that could make other operations easier is to defined Enum and Bounded instances for Suit and Rank:

data Suit = Hearts | Spades | Diamonds | Clubs deriving (Eq, Show, Enum, Bounded)
data Rank = Numeric Integer | Jack | Queen | King | Ace deriving (Eq, Show)
data Card = Card Rank Suit deriving (Eq, Show)
data Deck = None | Cons Card Deck deriving (Eq, Show)

instance Bounded Rank where
    minBound = Numeric 2
    maxBound = Ace

instance Enum Rank where
    toEnum n
        | n <= 1 = error "Invalid card value"
        | n <= 10 = Numeric $ toInteger n
        | n == 11 = Jack
        | n == 12 = Queen
        | n == 13 = King
        | n == 14 = Ace
        | otherwise = error "Invalid card value"
    fromEnum (Numeric i) = fromEnum i
    fromEnum Jack = 11
    fromEnum Queen = 12
    fromEnum King = 13
    fromEnum Ace = 14

range :: (Bounded a, Enum a) => [a]
range = [minBound .. maxBound]

fromList :: [Card] -> Deck
fromList = foldr Cons None

fullDeck :: Deck
fullDeck = fromList [Card r s | r <- range, s <- range]

It's rather easy to let the compiler just derive the instances for Suit, but it's a little more involved (but straightforward) for Rank. Strictly speaking, you don't need range, but I think it's kinda cool. Another advantage is that you can do things like [Numeric 2, Numeric 5, .. Ace] and get back [Numeric 2, Numeric 5, Numeric 8, Jack, Ace].

EDIT

If you can't change the definition of the data types to add the deriving statements, you can do it like this:

{-# LANGUAGE StandaloneDeriving #-}
data Suit = Hearts | Spades | Diamonds | Clubs

-- etc

deriving instance Eq Suit
deriving instance Show Suit
deriving instance Enum Suit
deriving instance Bounded Suit


来源:https://stackoverflow.com/questions/19775249/list-data-type-haskell-with-bounds

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!