实际上,当我开发扑克机器人时,我碰巧有一个方便的实现。它不是特别复杂,但确实有效。
一是相关类型。等级和花色是枚举,而卡片是明显的复合类型(带有自定义Show
实例)
import Text.ParserCombinators.Parsec
data Suit = Clubs | Diamonds | Hearts | Spades deriving (Eq,Ord,Enum,Show)
data Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace deriving (Eq,Ord,Enum,Show)
data Card = Card { rank :: Rank
, suit :: Suit } deriving (Eq,Ord,Bounded)
instance Show Card where
show (Card rank suit) = show rank ++ " of " ++ show suit
然后我们有解析代码,它使用 Parsec。您可以将其开发得更复杂,以返回更好的错误消息等。
请注意,正如 Matvey 在评论中所说,将字符串解析为其在程序中的表示的问题是(或者更确切地说应该是)正交于枚举的表示方式。在这里,我欺骗并破坏了正交性:如果您想重新排序排名(例如,Ace
排名低于Two
),那么您将破坏解析代码,因为解析器依赖于Two
being 0
,Three
being1
等的内部表示。
更好的方法是明确拼出所有等级parseRank
(这是我在原始代码中所做的)。我这样写是为了(a)节省一些空间,(b)说明原则上如何将数字解析为等级,以及(c)给你一个明确说明的不良做法的例子,这样你就可以避免它在将来。
parseSuit :: Parser Suit
parseSuit = do s <- oneOf "SDCH"
return $ case s of
'S' -> Spades
'D' -> Diamonds
'H' -> Hearts
'C' -> Clubs
parseRank :: Parser Rank
parseRank = do r <- oneOf "23456789TJQKA"
return $ case r of
'T' -> Ten
'J' -> Jack
'Q' -> Queen
'K' -> King
'A' -> Ace
n -> toEnum (read [n] - 2)
parseCard :: Parser Card
parseCard = do r <- parseRank
s <- parseSuit
return $ Card { rank = r, suit = s }
readCard :: String -> Either ParseError Card
readCard str = parse parseCard "" str
它在行动中:
*Cards> readCard "2C"
Right Two of Clubs
*Cards> readCard "JH"
Right Jack of Hearts
*Cards> readCard "AS"
Right Ace of Spades
编辑:
@yatima2975 在评论中提到,你也许可以玩得开心OverloadedStrings
。我无法让它做很多有用的事情,但它似乎很有希望。首先,您需要通过放在{-# LANGUAGE OverloadedStrings #-}
文件顶部来启用语言选项,并包含import GHC.Exts ( IsString(..) )
导入相关类型类的行。然后你可以把 aCard
变成一个字符串文字:
instance IsString Card where
fromString str = case readCard str of Right c -> c
这允许您对卡片的字符串表示进行模式匹配,而不必显式写出类型:
isAce :: Card -> Bool
isAce "AH" = True
isAce "AC" = True
isAce "AD" = True
isAce "AS" = True
isAce _ = False
您还可以使用字符串文字作为函数的输入:
printAces = do
let cards = ["2H", "JH", "AH"]
mapM_ (\x -> putStrLn $ show x ++ ": " ++ show (isAce x)) cards
它在行动中:
*Cards> printAces
Two of Hearts: False
Jack of Hearts: False
Ace of Hearts: True