为什么在使用attoparsec时我看到了部分结果,而不是失败?

14

我对 attoparsec 的这种行为感到有点困惑。

$ ghci
> :m Data.Attoparsec.Text
> :m + Data.Text
> parse (string (pack "module")) (pack "mox")
Partial _
> parse (string (pack "module")) (pack "moxxxx")
Fail "moxxxx" [] "Failed reading: takeWith"
> 

为什么我需要其他字符来触发失败?

难道不应该在遇到第一个 "x" 时就立即失败吗?


为了以后的参考,我打开了一个工单,Attoparsec维护者修复了这个bug:https://github.com/bos/attoparsec/issues/97 - Leon Mergen
1个回答

13

这是一个实现细节,string解析器在确定是否有足够的输入来成功之前不会完成。这是由于这些解析器的全有或全无行为所导致的(我认为,这通常对性能有益)。

string :: Text -> Parser Text
string s = takeWith (T.length s) (==s)

string s 尝试提取 s 的长度个单位的文本,然后与 s 进行比较。

takeWith :: Int -> (Text -> Bool) -> Parser Text
takeWith n p = do
  s <- ensure n
  let h = unsafeTake n s
      t = unsafeDrop n s
  if p h
    then put t >> return h
    else fail "takeWith"

takeWith n p 首先尝试确保有 n 个单位的 Text 可用,并且

ensure :: Int -> Parser Text
ensure !n = T.Parser $ \i0 a0 m0 kf ks ->
    if lengthAtLeast (unI i0) n
    then ks i0 a0 m0 (unI i0)
    else runParser (demandInput >> go n) i0 a0 m0 kf ks
  where
    go n' = T.Parser $ \i0 a0 m0 kf ks ->
        if lengthAtLeast (unI i0) n'
        then ks i0 a0 m0 (unI i0)
        else runParser (demandInput >> go n') i0 a0 m0 kf ks

ensure n 创建了一个续延,如果没有立即找到足够的输入,它将请求更多的输入(一个Partial结果)。

你可以通过以下方式获得失败:

Prelude Data.Attoparsec.Text Data.Text> parseOnly (string (pack "module")) (pack "mox")
Left "not enough input"

告诉解析器它不会再得到任何输入(然后从ensure中的demandInput使其失败),或者稍后。
Prelude Data.Attoparsec.Text Data.Text> parse (string (pack "module")) (pack "mox")
Partial _
Prelude Data.Attoparsec.Text Data.Text> feed it (pack "")
Fail "mox" ["demandInput"] "not enough input"

通过告诉“Partial”结果就是这样,将空的“Text”输入给它。

谢谢 - 在您的解释之后,这很有道理。 - timbod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接