我制作了Read
和Show
个数据实例,但不了解Read
个实例
data Tests = Zero
| One Int
| Two Int Double
instance Show Tests where
show Zero = "ZERO"
show (One i) = printf "ONE %i" i
show (Two i j) = printf "TWO %i %f" i j
instance Read Tests where
readsPrec _ str = [(mkTests str, "")]
mkTests :: String -> Tests
mkTests = check . words
check :: [String] -> Tests
check ["ZERO"] = Zero
check ["ONE", i] = One (read i)
check ["TWO", i, j] = Two (read i) (read j)
check _ = error "no parse"
main :: IO ()
main = do
print Zero
print $ One 10
print $ Two 1 3.14
let x = read "ZERO" :: Tests
print x
let y = read "ONE 2" :: Tests
print y
let z = read "TWO 2 5.5" :: Tests
print z
这是输出
ZERO
ONE 10
TWO 1 3.14
ZERO
ONE 2
TWO 2 5.5
以下是问题:
实施Read
实例的推荐方法是什么?
Read
类的最小完整定义为readsPrec | readPrec
和readPrec :: ReadPrec a
描述写道建议使用新式解析器替换readsPrec(仅限GHC)。
readPrec
代替吗?我无法在网上找到任何我能理解的例子。new-style parsers
,是parsec
? readsPrec :: Int -> ReadS a 的第一个Int
参数用于什么?
无论如何从Read
以某种方式得出Show
?
过去我可以使用deriving (Show,Read)
来完成大部分工作。但是这一次我想进入下一个阶段。
答案 0 :(得分:-1)
Int
的{{1}}参数用于在解析时处理优先级。当您想要解析算术表达式时,这可能很重要。如果优先级高于当前运算符的优先级,则可以选择无法解析。readsPrec
从Read
导出Show
。以下是一些代码段,展示了如何使用Read
实现ReadPrec
。
ReadPrec示例:
instance Read Tests where
readPrec = choice [pZero, pOne, pTwo] where
pChar c = do
c' <- get
if c == c'
then return c
else pfail
pZero = traverse pChar "ZERO" *> pure Zero
pOne = One <$> (traverse pChar "ONE " *> readPrec)
pTwo = Two <$> (traverse pChar "TWO " *> readPrec) <*> readPrec
一般来说,实现Read比不那么重量级的解析器更不直观。根据你要解析的内容,我强烈建议学习parsec或attoparsec,因为当你想要解析更复杂的东西时它们非常有用。