限制数据构造函数可以具有的元素数量

时间:2013-01-27 12:43:23

标签: haskell

我在Haskell写一个ADT代表一手牌。我的问题是,我想将代表卡片的(Suit,Face)的数量限制为5代表一只手。

data Card = Hand [(Suit,Face)]

我试图做的是这个,但它不起作用。

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

我的问题是:如何将元组数量限制为5?

3 个答案:

答案 0 :(得分:14)

我想补充一点,如果您使用基于5元组的解决方案(如其他答案所示),您仍然可以拥有所需的所有折叠/遍历功能。特别是,首先定义

import Control.Applicative
import Data.Foldable
import Data.Traversable

data Tuple5 a = Tuple5 a a a a a

并在其上定义foldingtraversing操作:

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

然后,你可以

data Hand = Hand (Tuple5 Card)

使用Foldable / Traversable / Functor中的任何方法折叠/遍历结构。


更新:最近,我创建了一个小型库tuples-homogenous-h98,为同源元组定义了newtype个别名,例如

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

并添加适当的TraversableFoldableFunctorApplicativeMonad个实例。

答案 1 :(得分:5)

怎么样

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

或者,如果你真的想使用一个列表(我的意思是,如果你想要15张牌,我的建议变得非常愚蠢),你可以保留data Card = Hand [(Suit, Face)],然后告诉用户不是< / em>使用构造函数,而是提供像“

”这样的“智能构造函数”
fromList :: [(Suit, Face]) -> Maybe Card
fromList xs 
        | length xs == 5 = Just (Hand xs)
        | otherwise      = Nothing

然后,您也可以使构造函数本身保持可用状态,例如“仅当您保证提供的列表包含精确的5个元素时才使用”。

顺便说一句:是不是将数据类型Card和构造函数Hand命名为有点违反直觉?我认为在您的情况下应该将数据类型称为HandCardSuit - Face对的一个很好的别名,因此您可以type Card = (Suit, Face)data Hand = Hand [Card]

答案 2 :(得分:5)

您可以为卡片创建一种类型,并为五种卡片元素创建一种手型:

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