开发者

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!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜