如何在 Haskell 中将枚举列表转换为另一种类型的枚举?
How to transform a list of enums to another type of enum in Haskell?
我正在尝试编写一个函数来创建一副完整的纸牌(52 张,没有王牌)。我对此还是陌生的,我认为某种列表理解是我需要做的,但我不太清楚如何编写它(参见 createHandFromList
函数)。我还猜测它需要递归才能继续进行。无论如何,到目前为止,我的代码是这样的,一如既往,我们非常感谢任何帮助和建议。
data Card = Card Rank Suit
deriving (Eq, Show)
data Rank = Numeric Integer | Jack | Queen | King | Ace
deriving (Eq, Show)
data Suit = Hearts | Spades | Diamonds | Clubs
deriving (Eq, Show)
data Hand = Empty | Add Card Hand
deriving (Eq, Show)
fullDeck :: Hand
fullDeck = createHandFromList (suitedCardList Clubs ++
suitedCardList Diamonds ++
suitedCardList Hearts ++
suitedCardList Spades)
suitedCardList :: Suit -> [Card]
suitedCardList s = [Card (Numeric 2) s, Card (Numeric 3) s,
Card (Numeric 4) s, Card (Numeric 5) s,
Card (Numeric 6) s, Card (Numeric 7) s,
Card (Numeric 8) s, Card (Numeric 8) s,
Card (Numeric 10) s, Card Jack s,
Card Queen s, Card King s, Card Ace s]
createHandFromList :: [Card] -> Hand -> Hand
createHandFromList [c:cs] h = [Add card h | card <- c]
目前,代码 returns 这是一个错误:
BlackJack.hs:107:21: error:
• Couldn't match expected type ‘Card’ with actual type ‘[[Card]]’
• In the pattern: c : cs
In the pattern: [c : cs]
In an equation for ‘createHandFromList’:
createHandFromList [c : cs] h = [Add card h | card <- c]
|
107 | createHandFromList [c:cs] h = [Add card h | card <- c] | ^^^^
BlackJack.hs:107:31: error:
• Couldn't match expected type ‘Hand’ with actual type ‘[Hand]’
• In the expression: [Add card h | card <- c]
In an equation for ‘createHandFromList’:
createHandFromList [c : cs] h = [Add card h | card <- c]
|
107 | createHandFromList [c:cs] h = [Add card h | card <- c] |
此代码存在多个问题。首先,您在 createHandFromList
的定义中使用了 [c:cs]
作为模式。然而,这是一个语法错误:在模式匹配中,语法是(c:cs)
。这给出了以下代码:
createHandFromList :: [Card] -> Hand -> Hand
createHandFromList (c:cs) h = [Add card h | card <- c]
但是这段代码还有一个问题。你 return 一个 Hand
的列表,但是类型签名说你必须 return 一个 Hand
!显然这是错误的。为了弄清楚该怎么做,让我们退后一步,仔细研究 createHandFromList
应该做什么:
- 从给出的手牌开始,向该手牌添加一张牌
- 将另一张牌添加到刚创建的手牌中
- 将另一张牌添加到刚创建的手牌中
- …
- 重复直到没有牌为止。
这可以通过递归最容易地完成:
createHandFromList :: [Card] -> Hand -> Hand
-- Add card ‘c’ to the result of (createHandFromList cs h)
createHandFromList (c:cs) h = Add c (createHandFromList cs h)
-- Return hand ‘h’ if there are no more cards left to add
createHandFromList [] h = h
我还想解决一个小的简化问题。 (感谢@Khuldraeseth na'Barya,他在评论中写了这个。)让我们看看 Hand
:
的可能值
Empty
Add card1 Empty
Add card2 (Add card1 Empty)
Add card3 (Add card2 (Add card1 Empty))
- 等等
这看起来就像 Card
的列表!事实证明类型 Hand
和 [Card]
是同构的。在伪Haskell:
data Hand = Empty | Add Card Hand
data [Card] = [] | : Card [Card]
因此,如果您将 Hand
表示为 newtype Hand = Hand { getCards :: [Card] }
之类的东西,那么您应该能够用列表理解替换递归。这留作 reader.
的练习
我正在尝试编写一个函数来创建一副完整的纸牌(52 张,没有王牌)。我对此还是陌生的,我认为某种列表理解是我需要做的,但我不太清楚如何编写它(参见 createHandFromList
函数)。我还猜测它需要递归才能继续进行。无论如何,到目前为止,我的代码是这样的,一如既往,我们非常感谢任何帮助和建议。
data Card = Card Rank Suit
deriving (Eq, Show)
data Rank = Numeric Integer | Jack | Queen | King | Ace
deriving (Eq, Show)
data Suit = Hearts | Spades | Diamonds | Clubs
deriving (Eq, Show)
data Hand = Empty | Add Card Hand
deriving (Eq, Show)
fullDeck :: Hand
fullDeck = createHandFromList (suitedCardList Clubs ++
suitedCardList Diamonds ++
suitedCardList Hearts ++
suitedCardList Spades)
suitedCardList :: Suit -> [Card]
suitedCardList s = [Card (Numeric 2) s, Card (Numeric 3) s,
Card (Numeric 4) s, Card (Numeric 5) s,
Card (Numeric 6) s, Card (Numeric 7) s,
Card (Numeric 8) s, Card (Numeric 8) s,
Card (Numeric 10) s, Card Jack s,
Card Queen s, Card King s, Card Ace s]
createHandFromList :: [Card] -> Hand -> Hand
createHandFromList [c:cs] h = [Add card h | card <- c]
目前,代码 returns 这是一个错误:
BlackJack.hs:107:21: error:
• Couldn't match expected type ‘Card’ with actual type ‘[[Card]]’
• In the pattern: c : cs
In the pattern: [c : cs]
In an equation for ‘createHandFromList’:
createHandFromList [c : cs] h = [Add card h | card <- c]
|
107 | createHandFromList [c:cs] h = [Add card h | card <- c] | ^^^^
BlackJack.hs:107:31: error:
• Couldn't match expected type ‘Hand’ with actual type ‘[Hand]’
• In the expression: [Add card h | card <- c]
In an equation for ‘createHandFromList’:
createHandFromList [c : cs] h = [Add card h | card <- c]
|
107 | createHandFromList [c:cs] h = [Add card h | card <- c] |
此代码存在多个问题。首先,您在 createHandFromList
的定义中使用了 [c:cs]
作为模式。然而,这是一个语法错误:在模式匹配中,语法是(c:cs)
。这给出了以下代码:
createHandFromList :: [Card] -> Hand -> Hand
createHandFromList (c:cs) h = [Add card h | card <- c]
但是这段代码还有一个问题。你 return 一个 Hand
的列表,但是类型签名说你必须 return 一个 Hand
!显然这是错误的。为了弄清楚该怎么做,让我们退后一步,仔细研究 createHandFromList
应该做什么:
- 从给出的手牌开始,向该手牌添加一张牌
- 将另一张牌添加到刚创建的手牌中
- 将另一张牌添加到刚创建的手牌中
- …
- 重复直到没有牌为止。
这可以通过递归最容易地完成:
createHandFromList :: [Card] -> Hand -> Hand
-- Add card ‘c’ to the result of (createHandFromList cs h)
createHandFromList (c:cs) h = Add c (createHandFromList cs h)
-- Return hand ‘h’ if there are no more cards left to add
createHandFromList [] h = h
我还想解决一个小的简化问题。 (感谢@Khuldraeseth na'Barya,他在评论中写了这个。)让我们看看 Hand
:
Empty
Add card1 Empty
Add card2 (Add card1 Empty)
Add card3 (Add card2 (Add card1 Empty))
- 等等
这看起来就像 Card
的列表!事实证明类型 Hand
和 [Card]
是同构的。在伪Haskell:
data Hand = Empty | Add Card Hand
data [Card] = [] | : Card [Card]
因此,如果您将 Hand
表示为 newtype Hand = Hand { getCards :: [Card] }
之类的东西,那么您应该能够用列表理解替换递归。这留作 reader.