Limit the number of items a data constructor can have

I am writing ADT in Haskell, which is a hand of cards. My problem is that I would like to limit the number (Suit,Face) , which is a 5 card, which is a hand.

 data Card = Hand [(Suit,Face)] 

I tried to do this, but that will not work.

 data Card = Hand [(Suit,Face),(Suit,Face),(Suit,Face),(Suit,Face),(Suit,Face)] 

My question is: how to limit the number of tuples to 5?

+8
haskell
source share
3 answers

I would like to add that if you use a solution based on 5 tuples (as suggested in other answers), you can still use all the folding / moving functions. In particular, first define

 import Control.Applicative import Data.Foldable import Data.Traversable data Tuple5 a = Tuple5 aaaaa 

and define folding and moving operations on it:

 instance Traversable Tuple5 where traverse f (Tuple5 abcde) = Tuple5 <$> fa <*> fb <*> fc <*> fd <*> fe instance Foldable Tuple5 where foldMap = foldMapDefault instance Functor Tuple5 where fmap = fmapDefault 

Then you can have

 data Hand = Hand (Tuple5 Card) 

and reset / move the structure using any methods from Foldable / Traversable / Functor .


Update: I recently created a small tuples-homogenous-h98 library that defines newtype aliases for uniform tuples such as

 newtype Tuple5 a = Tuple5 { untuple5 :: (a,a,a,a,a) } 

and adds examples of Traversable , Foldable , Functor , Applicative and Monad .

+14
source share

What about

 data Card = Hand (Suit, Face) (Suit, Face) (Suit, Face) (Suit, Face) (Suit, Face) 

?

Or, if you really want to use the list (I mean, if you need 15-card hands, my suggestion becomes very stupid), you can save data Card = Hand [(Suit, Face)] , and then tell users not to use constructor, and instead provide a "smart constructor", for example

 fromList :: [(Suit, Face]) -> Maybe Card fromList xs | length xs == 5 = Just (Hand xs) | otherwise = Nothing 

Then you can also leave the constructor available with a warning, for example: "use only if you guarantee that the list contains exactly 5 elements."

By the way: doesn't the Card data type call the Hand constructor a bit unintuitive? I think the data type should be called Hand in your case. Card is a good alias for the Suit - Face pair, so you can do type Card = (Suit, Face) and data Hand = Hand [Card] .

+5
source share

You can create a type for cards and a type of hand with five map elements:

 type Card = (Suit, Face) data Hand = Hand Card Card Card Card Card 
+5
source share

All Articles