我正在学习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
现在我想创造一张52张牌的原始牌组。我确信有一种光滑的方式可以做到,但我能想到的只有:
pristineDeck = [Card Ace Hearts, Card Two Hearts, ...]
我可以让Haskell为我生成这个列表吗?
答案 0 :(得分:10)
列表推导是一种非常整洁的语法。如果您在Enum
和Rank
上获得Suit
,则可以将其简单地表达为:
pristineDeck = [ Card rank suit | suit <- [Hearts .. Clubs], rank <- [Ace .. King] ]
如果您想知道为什么我在不同的订单中有suit
和rank
,第一个是因为Card
构造函数使用的顺序,而后者是为了获取订单结果列表 - 按升序排列。
更一般地说,或者当单个列表理解变得过于庞大时,笛卡尔积就是列表的Monad
实例给出的行为。以下等同于上面的列表推导:
pristineDeck = do suit <- [Hearts .. Clubs]
rank <- [Ace .. King]
return $ Card rank suit
作为另一个小问题,为了省去记住Suit
值所在的顺序的麻烦,导出Bounded
也可以编写[minBound .. maxBound]
来枚举所有值包含Enum
和Bounded
实例的任何类型。
答案 1 :(得分:7)
有几种方法可以做到这一点,不同程度的巫术。
首先,由于您的类型的构造函数都没有参数,因此您可以为它们派生Enum
。这将允许你写例如[Ace..King]
获取所有卡片的清单。
其次,列表推导是形成从多个其他列表中绘制的项目列表的好方法。试试这个:
[x + y | x <- [100,200,300], y <- [1,2,3]]
这应该为您提供应用于您的示例所需的工具。
答案 2 :(得分:3)
Alp是正确的告诉你派生Enum
>data Rank = Ace|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten|Jack|Queen|King deriving (Eq,Show,Ord,Enum)
>data Suit = Hearts|Spades|Diamonds|Clubs deriving (Show,Enum)
现在:
>enumFrom Ace
[Ace,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King]
要获得两个列表的排列,您可以使用列表推导:
>[[x,y]|x<-[1..2],y<-[2..5]]
[[1,2],[1,3],[1,4],[1,5],[2,2],[2,3],[2,4],[2,5]]
或获得添加的排列:
>[x + y|x<-[1..2],y<-[2..5]]
[3,4,5,6,4,5,6,7]
现在你只需要进行一些替换来获得排名和套装的Car的排列。