Haskell:如何生成两个简单代数数据类型的笛卡尔积

Ton*_* K. 5 haskell

我正在学习Haskell,所以我正在写一些简单的纸牌游戏.我已经定义了一些数据类型:

data Rank = Ace|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten|Jack|Queen|King deriving (Eq,Show,Ord)

data Suit = Hearts|Spades|Diamonds|Clubs deriving (Show)

data Card = Card Rank Suit 
Run Code Online (Sandbox Code Playgroud)

现在我想创建一张52张牌的原始牌组.我确信有一种光滑的方式可以做到,但我能想到的只有:

 pristineDeck = [Card Ace Hearts, Card Two Hearts, ...]
Run Code Online (Sandbox Code Playgroud)

我可以让Haskell为我生成这个列表吗?

C. *_*ann 10

列表推导是一种非常整洁的语法.如果你得到EnumRankSuit你可以很简单地表达出来:

pristineDeck = [ Card rank suit | suit <- [Hearts .. Clubs], rank <- [Ace .. King] ]
Run Code Online (Sandbox Code Playgroud)

如果你想知道为什么我suitrank按不同的顺序,首先是因为订单的Card构造函数使用,而后者则是得到结果列表的顺序-升序西装在一起.

更一般地说,或者当单个列表理解变得过于庞大时,笛卡尔积恰好是Monad列表实例给出的行为.以下等同于上面的列表理解:

pristineDeck = do suit <- [Hearts .. Clubs]
                  rank <- [Ace .. King]
                  return $ Card rank suit
Run Code Online (Sandbox Code Playgroud)

作为一个其他的小点,保存自己的记忆的麻烦什么顺序Suit值在,导出Bounded以及将使写[minBound .. maxBound]枚举任何类型的所有值与两个实例EnumBounded.

  • 而且我还会得到一个"有界"实例.`[minBound .. maxBound]`清楚表明你列举了所有的变种,即使没有自然顺序. (2认同)
  • `Card <$> [minBound..maxBound] <*> [minBound..maxBound]` (2认同)

Ben*_*ood 7

有几种方法可以做到这一点,不同程度的魔法.

首先,由于您的类型的构造函数都没有参数,您可以Enum为它们派生.这将允许您编写例如[Ace..King]以获取所有卡的列表.

其次,列表推导是形成从多个其他列表中绘制的项目列表的好方法.试试这个:

[x + y | x <- [100,200,300], y <- [1,2,3]]
Run Code Online (Sandbox Code Playgroud)

这应该为您提供应用于您的示例所需的工具.