使用Haskell读取组合数据类型的实例

时间:2015-10-07 21:00:36

标签: haskell instance ghc

我在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

通过实例,我可以showread类型PrefixTypeCombin数据类型是PrefixType的串联。 现在,我想实现Combin数据类型的读取实例,我不知道如何做到这一点。

我考虑过导出Combin类型,但它导致Combin PrefA ValC的输出字符串为" Combin a mp"。而这不是我想要的。我想" amp"连在一起。阅读同样的事情

我考虑过使用输入字符串进行模式匹配,但Prefix字符串的长度不同,可能无效(NoPref)。

你有没有用read实现这样的功能?你知道怎么做吗?

1 个答案:

答案 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