【发布时间】:2020-01-31 22:53:03
【问题描述】:
我对函数式编程非常陌生,并且我很少有以下自定义数据类型来表示一副纸牌。
西装的数据类型
data Suit = Spade | Club | Diamond | Heart
deriving (Eq, Ord, Enum, Bounded)
instance Show Suit where
show Spade = "S"
show Club = "C"
show Diamond = "D"
show Heart = "H"
instance Read Suit where
readsPrec _ [] = []
readsPrec _ (s: str) = case s of
'S' -> [(Spade, str)]
'C' -> [(Club, str)]
'D' -> [(Diamond, str)]
'H' -> [(Heart, str)]
_ -> []
排名的数据类型
data Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
deriving (Eq, Ord, Enum, Bounded)
instance Show Rank where
show Ace = "A"
show King = "K"
show Queen = "Q"
show Jack = "J"
show rank = show $ fromEnum rank + 2
instance Read Rank where
readsPrec _ [] = []
readsPrec _ (s: str) = case s of
'A' -> [(Ace, str)]
'K' -> [(King, str)]
'Q' -> [(Queen, str)]
'J' -> [(Jack, str)]
_ -> readNum
where
readNum
| s >= '2' && s <= '9' = [(toEnum (ord s - ord '2') :: Rank, str)]
| s == '1' = readZero str -- Read a following 0
| otherwise = []
readZero ('0': rest) = [(Ten, rest)]
readZero _ = []
卡片的数据类型
data Card = Card Suit Rank
deriving (Eq)
instance Show Card where
show (Card suit rank) = show suit ++ show rank
instance Read Card where
readsPrec _ str = do
(s, rest) <- reads str
(r, end) <- reads rest
return (Card s r, end)
当我在我的堆栈 ghci 控制台中输入 read "S3H5" :: Card 时,它显示了一个异常错误 *** Exception: Prelude.read: no parse。
请问如何解决这个问题?
我有一串卡片信息,例如“S3HA”代表两张卡片:
- 铁锹三
- 心脏王牌
我想要达到的目标:
当我读取“S3HA”的字符串时,我希望输出是一个数组
[Card Spade Three, Card Heart Ace]
请指教!我对 Haskell 函数式编程比较陌生!
并且我不想修改上述Card、Suit 和Rank 的自定义数据类型的源代码,而是利用这些数据类型创建[Card] 的数组。谁能提供将字符串解析为[Card]的方法?
【问题讨论】:
-
read "S3" :: Card工作正常。问题是您不能说read "S3H5" :: [Card],因为Read的列表实例假定该字符串包含一个实际的列表文字,而不仅仅是您要读取的列表的a类型的并列字符串。 -
那我如何阅读才能产生输出
[Card Spade Three, Card Heart Ace]? -
我认为你可以使用
FlexibleInstances扩展来为Read定义你自己的[Card]实例(它还必须以某种方式使用状态单子来遍历字符串;@987654341 @ 正在尝试从字符串中的 每个 字符创建卡片,而不仅仅是从字符串中读取单个字符并继续)。不过,我建议使用适当的解析库,例如parsec或其变体之一,而不是Read。 -
鉴于我的任务要求不允许我修改源代码(对于
Card、Suit和Rank的自定义数据类型,我认为我不能这样做上面,但只利用这些数据类型来创建输出[Card]的数组。我不知道如何用解析方法来实现这个输出(我对haskell和解析的了解很浅),你能提供一个例子来说明如何解析[Card]的输出?谢谢。 -
对于列表,我认为您需要在
Read Card实例中重新定义readList方法。如果你这样做,那么预定义的instance Read a => Read [a]将自动调用你自己的readList,一切都应该正常工作。 hackage.haskell.org/package/base-4.12.0.0/docs/…
标签: parsing haskell functional-programming typeclass