Reputation: 2471
I am writing an ADT in Haskell which represents a hand of cards. My problem is that I would like to restrict the number of (Suit,Face)
which represents a card to 5 which represents a hand.
data Card = Hand [(Suit,Face)]
What I tried to do was this but it does not work.
data Card = Hand [(Suit,Face),(Suit,Face),(Suit,Face),(Suit,Face),(Suit,Face)]
My question is: how do i restrict the number of tuples to 5?
Upvotes: 8
Views: 169
Reputation: 63359
I'd like to add that if you use a solution based on 5-tuples (as suggested in the other answers), you can still have all folding/traversing functions you need. In particular, first define
import Control.Applicative
import Data.Foldable
import Data.Traversable
data Tuple5 a = Tuple5 a a a a a
and define folding and traversing operations on it:
instance Traversable Tuple5 where
traverse f (Tuple5 a b c d e)
= Tuple5 <$> f a <*> f b <*> f c <*> f d <*> f e
instance Foldable Tuple5 where
foldMap = foldMapDefault
instance Functor Tuple5 where
fmap = fmapDefault
Then, you can have
data Hand = Hand (Tuple5 Card)
and fold/traverse the structure using any methods from Foldable
/Traversable
/Functor
.
Update: Recently I created a small library tuples-homogenous-h98 that defines newtype
aliases for homogenous tuples such as
newtype Tuple5 a = Tuple5 { untuple5 :: (a,a,a,a,a) }
and adds proper Traversable
, Foldable
, Functor
, Applicative
and Monad
instances.
Upvotes: 14
Reputation: 11227
How about
data Card = Hand (Suit, Face) (Suit, Face) (Suit, Face) (Suit, Face) (Suit, Face)
?
Or, if you really want to use a list (I mean, if you wanted 15-card hands, my suggestion becomes very silly), you can keep data Card = Hand [(Suit, Face)]
and then tell users to not use the constructor, and instead provide a "smart constructor" like
fromList :: [(Suit, Face]) -> Maybe Card
fromList xs
| length xs == 5 = Just (Hand xs)
| otherwise = Nothing
You could then also leave the constructor itself available with a warning like "use only if you guarantee that the supplied list contains precisely 5 elements".
By the way: Isn't naming the data type Card
and the constructor Hand
a bit counterintuitive? I think the data type should be called Hand
in your case. Card
is a nice alias for a Suit
-Face
pair, so you could do type Card = (Suit, Face)
and data Hand = Hand [Card]
.
Upvotes: 5
Reputation: 144126
You could create a type for Cards and a Hand type with five Card elements:
type Card = (Suit, Face)
data Hand = Hand Card Card Card Card Card
Upvotes: 5