實際上,從我開發撲克機器人的時候開始,我實際上已經有了一個實現。這不是特別複雜,但確實有效。
一,相關類型。秩和西裝是枚舉,而卡是明顯的複合型(使用自定義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
然後我們分析代碼,它使用秒差距。你可以開發這個更復雜,返回更好的錯誤信息,等等。
請注意,正如馬特維在評論中所說,解析字符串到它們在程序中的表示的問題是(或者更確切地說應該是)與如何表示枚舉正交。在這裏,我欺騙並破壞了正交性:如果您想重新排列等級(例如Ace
排名低於Two
),那麼您會破壞解析代碼,因爲解析器取決於Two
的內部表示形式,即0
,Three
1
等。
更好的方法是明確地說出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
編輯:
@在你也許能有一些有趣的OverloadedStrings
打的評論中提到yatima2975 。我沒有能夠做到這一點很有用,但看起來很有希望。首先,您需要啓用語言選項,方法是將{-# LANGUAGE OverloadedStrings #-}
放在文件的頂部,幷包含行import GHC.Exts (IsString(..))
以導入相關的類型類別。然後,你可以做一個Card
成字符串文字:
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
C也不能這樣做。 – 2012-04-25 10:02:05
將「1S」或「2D」等字符串解析爲卡片的功能實際上與枚舉表示法是正交的。 – 2012-04-25 12:16:33
@MatveyAksenov嗯,我明白這一點。我所尋找的是在類型系統中最習慣的方式。無論如何,我想我問了錯誤的問題。 – m09 2012-04-25 12:39:33