Haskell: making a deck of cards
I am new to Haskell and having problems using recursion to make a deck of cards.
I have all these definitions:
data Suit = Club | Diamond | Heart | Spade
data Value = Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen
| King | Ace
type Card = (Suit, Value)
type Deck = [Card]
instance Show Suit where
show Club = "Club"
show Diamond = "Diamond"
show Heart = "Heart"
show Spade = "Spade"
instance Show Value w开发者_如何学JAVAhere
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 am trying to write a function
makeDeck :: Deck
which returns a list of cards in the order the Data is given, so (Club, Two - Ace), (Diamond, Two-Ace), etc.
I want to do this using recursion, which is why I am having so much difficulty.
Any help would be greatly appreciated.
Thank you!
This doesn't use recursion, but a more canonical way of doing this is:
Add deriving Enum
to the definition of Suit and Value, then:
makeDeck :: Deck
makeDeck = [(suit, value) | suit <- [Club..Spade], value <- [Two..Ace]]
Alternatively, provide fully defined lists of all suits and values rather than using Enum
.
Given:
data Suit = Club | Diamond | Heart | Spade deriving (Show, Enum)
data Value = Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen
| King | Ace deriving (Show, Enum)
type Card = (Suit, Value)
type Deck = [Card]
makeDeck :: Deck
there are lots of ways to calculate a Cartesian Product -- the product of sets. All of the functions used in these examples can be looked up on Hoogle:
Monads
Using do notation:
makeDeck = do
suit <- [Club ..]
value <- [Two ..]
return (suit, value)
The unsugared form of the above, which uses >>=
:
makeDeck = [Club ..] >>= \suit ->
[Two ..] >>= \value ->
return (suit, value)
Lifting:
makeDeck = liftM2 (,) [Club ..] [Two ..]
Function application within monads:
makeDeck = return (,) `ap` [Club ..] `ap` [Two ..]
Applicatives
Lifting:
makeDeck = liftA2 (,) [Club ..] [Two ..]
Function application within applicatives:
makeDeck = pure (,) <*> [Club ..] <*> [Two ..]
Which is the same as:
makeDeck = (,) <$> [Club ..] <*> [Two ..]
List comprehensions
See @ivanm's answers.
Without any type classes
makeDeck = concatMap (\suit -> map ((,) suit) [Two ..]) [Club ..]
If you need to use recursion explicitly, you can replace concatMap
with its definition, and so on until you get to foldr
, where the real recursive action happens.
Firstly, are you aware of list comprehensions and all the awesome things you can do with them? The makeDeck
function could be written as a fairly simple list comprehension (as ivanm pointed out in his answer), especially given the order you'd like the deck to be in.
However, if you'd still like to use recursion, there are a few ways to go about it. First, figure out what variables you'll need to keep track of during the whole operation. You'll need to keep the current list of cards, and a record of which suit and value you're at. So the type signature might look something like makeDeck :: Suit -> Value -> Deck
. Then you'd want to use pattern matching to handle the several possible cases during the computation, such as
makeDeck suit Ace deck = (suit,Ace):(makeDeck (succ suit) Two)
[...]
As you can see, this might turn out to be a fairly long and unwieldy definition. The list comprehension method would yield a much more short, elegant, and canonical solution. Regardless of which you choose, you'll need to add deriving Enum
to the end of your datatype declarations. Read up on the deriving
keyword here or elsewhere online if you're not familiar with it.
Others have pointed you towards list comprehensions, but if you would like to write it recursively, read on.
This sounds like homework, so I'll just try and give you tips that point you in the right direction (as opposed to writing it for you).
Thing to realize #1:
If you derive the Enum typeclass for your algebraic data types, you can create enumerations like so:
*Main> [Club .. Spade]
[Club,Diamond,Heart,Spade]
Thing to realize #2:
You can create lists of tuples like that, by using maps. You'll end up with [[Suit]], so you should use the concat
function to join them into a Deck
.
*Main> concat $ map (\x -> map (\y -> (x, y)) ['a'..'c']) [1..3]
[(1,'a'),(1,'b'),(1,'c'),(2,'a'),(2,'b'),(2,'c'),(3,'a'),(3,'b'),(3,'c')]
Thing to realize #3: You can implement map recursively. Here's the definition from the Prelude:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
So you could write the (map . map) as one big recursive function. Good luck!
精彩评论