我在Haskell程序中实现了这些(简化的)数据类型:
data Type = ValA
| Valb
| ValC
data Prefix = PrefA
| PrefB
| PrefC
| NoPref
data Combin = Combin Prefix Type
instance Show Type where
show ValA = "typeA"
show Valb = "O"
show ValC = "mp"
instance Read Type where
readsPrec _ "typeA" = [(ValA,"")]
readsPrec _ "O" = [(Valb,"")]
readsPrec _ "mp" = [(ValC,"")]
instance Show Prefix where
show PrefA = "a"
show PrefB = "bm"
show PrefC = "c"
show NoPref = ""
instance Read Prefix where
readsPrec _ "a" = [(PrefA,"")]
readsPrec _ "bm" = [(PrefB,"")]
readsPrec _ "c" = [(PrefC,"")]
readsPrec _ "" = [(NoPref,"")]
instance Show Combin where
show (Combin pre typ) = show pre++show typ
通过实例,我可以show
和read
类型Prefix
和Type
。 Combin
数据类型是Prefix
和Type
的串联。
现在,我想实现Combin
数据类型的读取实例,我不知道如何做到这一点。
我考虑过导出Combin类型,但它导致Combin PrefA ValC的输出字符串为" Combin a mp"。而这不是我想要的。我想" amp"连在一起。阅读同样的事情
我考虑过使用输入字符串进行模式匹配,但Prefix
字符串的长度不同,可能无效(NoPref
)。
你有没有用read实现这样的功能?你知道怎么做吗?
答案 0 :(得分:2)
您的readsPrec
实现是错误的,因为它们应该接受输入的有效前缀,不一定消耗整个输入。您的readsPrec
函数不可组合。
解决方案的关键是重写它们,以便检查它们的输入是否与任何名称匹配:
import Data.List (stripPrefix)
instance Read Type where
readsPrec _ s | Just s' <- stripPrefix "typeA" s = [(ValA, s')]
| Just s' <- stripPrefix "O" s = [(Valb, s')]
| Just s' <- stripPrefix "mp" s = [(ValC, s')]
| otherwise = []
,同样适用于Prefix
:
instance Read Prefix where
readsPrec _ s | Just s' <- stripPrefix "a" s = [(PrefA, s')]
| Just s' <- stripPrefix "bm" s = [(PrefB, s')]
| Just s' <- stripPrefix "c" s = [(PrefC, s')]
| otherwise = [(NoPref, s)]
请注意readsPrec
的{{1}}的最后一个分支,其中表示不会以Prefix
,"a"
或"bm"
开头的每个字符串将被解析为"c"
。这仅适用于NoPref
,因为没有Combin
以任何Type
位开头;否则,Prefix
的解析器需要是非确定性的,因为像Prefix
这样的字符串可能对应"aXY"
Prefix
和"a"
{ {1}},Type
"XY"
和Prefix
NoPref
。我选择了确定性的热切版本,因为我觉得它更容易理解它是如何工作的。
我们拥有这两个Type
个实例后,为"aXY"
写一个简单的问题是尝试使用Read
Combin
读取整个字符串的简单问题,然后试图将每个余数读作reads
:
Prefix
如果您熟悉Type
符号和instance Read Combin where
readsPrec _ s = [(Combin pre typ, s'') | (pre, s') <- reads s, (typ, s'') <- reads s']
monad,则可以将其重写为
do