了解Text.ParserCombinators.ReadP.sepBy1

时间:2019-03-10 10:39:42

标签: parsing haskell parser-combinators

我对sepBy1的结果感到困惑

以下代码在ghci中运行

λ> import Text.ParserCombinators.ReadP
λ> import Data.Char

λ> readP_to_S ((munch1 isAlpha) `sepBy1` (char '-')) "dish-dash-dosh"
[(["dish"],"-dash-dosh"),(["dish","dash"],"-dosh"),["dish","dash","dosh"],"")]

  1. 为什么输出[(["dish","dash","dosh"],"")]不是这种情况?

以下doctest只有一个失败的

-- |
-- >>> readP_to_S readValues "dish-dash-dosh"
-- [(V ["dish","dash","dosh"],"")
readValues :: ReadP Value
readValues = do
  xs <- (munch isAlpha) `sepBy1` (char '-')
  pure $ V xs
Main.hs:64: failure in expression `readP_to_S readValues "dish-dash-dosh"'
expected: [(V ["dish","dash","dosh"],"")
 but got: [(V ["dish"],"-dash-dosh"),(V ["dish","dash"],"-dosh"),(V ["dish","dash","dosh"],"")]

我将ReadP用于数据的Read实例。 Read实例的代码正常工作,但我感到困惑。

没有进行任何复杂的解析,我一直认为运行ReadP会以单元素列表[(result,"")]的形式返回输出,显然不是这样。

data Value = V [String]
  deriving Show

-- |
-- >>> read "dish-dash-dosh" :: Value
-- V ["dish","dash","dosh"]
--
instance Read Value where
  readPrec = readP_to_Prec (const readValues)

  1. 是否只有在最后一个read的{​​{1}}中没有任何东西的情况下snd才会成功,此列表中的其他元素在任何地方都没有使用?

我知道可以选择way来做到这一点。这个问题仅仅是关于了解[(Value,String)]的输出及其用法。

1 个答案:

答案 0 :(得分:3)

运行ReadP将返回所有可能的解析。您可以通过指定sepBy1解析后应进行的操作来限制有效解析的次数,例如输入结束或其他语法元素。

例如,尝试类似的操作:

readValues = do
  xs <- (munch isAlpha) `sepBy1` (char '-')
  eof
  pure $ V xs

附录...

ReadS类型遵循经典的Hutton and Meijer论文[dcl.ref]/1中介绍的单子语法解析方法。从很少的文档中,我了解到ReadP实现了所有替代方案的并行探索。创建ReadP操作有很多支持,而对于ReadS却没有太多支持,因此我认为您通过构建ReadP操作然后使用{{1 }} 在末尾。使用模块后,我刚进行了readP_to_S操作的第一个匹配项(或者如果是空列表,则返回解析错误)。

ReadS monad用于支持优先级,它基本上是ReadPrec,这里的ReaderT Int ReadP是当前优先级。同样,您似乎从Int解析器开始,然后使用ReadPReadPrec将其转换为lift操作。要运行它,您可以像使用readP_to_Prec一样使用readPrec_to_S