使用 Haskell 读取组合数据类型的实例
Read instance of a combined datatype with Haskell
我在 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 实现过这样的功能?你知道怎么做吗?
您的 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
的最后一个分支 Prefix
,它表示每个不以 "a"
、"bm"
或 "c"
开头的字符串将被解析为 NoPref
。这仅适用于 Combin
,因为没有 Type
以任何 Prefix
位开头;否则,Prefix
的解析器将需要是不确定的,因为像 "aXY"
这样的字符串可能对应于 "a"
的 Prefix
和 Type
"XY"
,或 NoPref
的 Prefix
和 "aXY"
的 Type
。我在这里选择了确定性渴望的版本,因为我认为它会让您更容易理解它是如何工作的。
一旦我们有了这两个 Read
实例,为 Combin
写一个是一件简单的事情,尝试用 reads
为 Prefix
读取整个字符串,然后尝试将每个余数读取为 Type
:
instance Read Combin where
readsPrec _ s = [(Combin pre typ, s'') | (pre, s') <- reads s, (typ, s'') <- reads s']
如果您熟悉 do
表示法和 []
monad,您可以将其重写为
instance Read Combin where
readsPrec _ s = do
(pre, s) <- reads s
(typ, s) <- reads s
return (Combin pre typ, s)
我在 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 实现过这样的功能?你知道怎么做吗?
您的 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
的最后一个分支 Prefix
,它表示每个不以 "a"
、"bm"
或 "c"
开头的字符串将被解析为 NoPref
。这仅适用于 Combin
,因为没有 Type
以任何 Prefix
位开头;否则,Prefix
的解析器将需要是不确定的,因为像 "aXY"
这样的字符串可能对应于 "a"
的 Prefix
和 Type
"XY"
,或 NoPref
的 Prefix
和 "aXY"
的 Type
。我在这里选择了确定性渴望的版本,因为我认为它会让您更容易理解它是如何工作的。
一旦我们有了这两个 Read
实例,为 Combin
写一个是一件简单的事情,尝试用 reads
为 Prefix
读取整个字符串,然后尝试将每个余数读取为 Type
:
instance Read Combin where
readsPrec _ s = [(Combin pre typ, s'') | (pre, s') <- reads s, (typ, s'') <- reads s']
如果您熟悉 do
表示法和 []
monad,您可以将其重写为
instance Read Combin where
readsPrec _ s = do
(pre, s) <- reads s
(typ, s) <- reads s
return (Combin pre typ, s)