Lightyear requireFailure 不做回溯

Lightyear requireFailure does not do backtracking

我想解析一系列任意 4 个字符。但是,这些字符不应形成特定的字符串(在下面的示例中为 "bb")。所以 "aaaa""abcd" 可以,但是 "bbcd""abbc" 都不应该匹配。

我编写了以下解析器:

ntimes 4 (requireFailure (string "bb") *> anyChar)

但是,我注意到,它 "eats" 单个 b 个字符。例如

parse (ntimes 4 (requireFailure (string "bb") *> anyToken)) "abcde"

结果为 ['a', 'c', 'd', 'e'](但是,如预期的那样,它在 "bbcd""abbc" 上失败)。

作为解决方法,我使用了自己的 requireFailure:

实现
requireFailure' : Parser a -> Parser ()
requireFailure' p = do
    isP <- p *> pure True <|> pure False
    if isP then fail "argument parser to fail"
           else pure ()

所以

parse (ntimes 4 (requireFailure' (string "bb") *> anyToken)) "abcde"

如我所料给出 ['a', 'b', 'c', 'd']

显然光年解析器是 backtrack-by-default,除非有人调用 commitTo

所以我的问题是,为什么 requireFailure 的库实现在参数失败时不进行回溯,这是预期的行为吗?

如果您查看 the implementation of requireFailure,您会看到它调用 "success" 延续 us 状态 s 它在 之后得到 运行 它的参数而不是它之前得到的参数 ST i pos tw

requireFailure : ParserT str m tok -> ParserT str m ()
requireFailure (PT f) = PT $ \r, us, cs, ue, ce, (ST i pos tw) =>
                               f r
                                 (\t, s => ue [Err pos "argument parser to fail"] s)
                                 (\t, s => ce [Err pos "argument parser to fail"] s)
                                 (\errs, s => us () s)
                                 (\errs, s => cs () s)
                                 (ST i pos tw)

文档声称 requireFailure 在秒差距和 that doesn't consume any input 中被称为 notFollowedBy,所以你可以说这是 LightYear 方面的一个错误。

您可以打开一个错误报告,建议用类似的东西替换当前代码(我不知道 Idris 是否支持 @ 模式):

requireFailure : ParserT str m tok -> ParserT str m ()
requireFailure (PT f) = PT $ \r, us, cs, ue, ce, s@(ST i pos tw) =>
                               f r
                                 (\t, s => ue [Err pos "argument parser to fail"] s)
                                 (\t, s => ce [Err pos "argument parser to fail"] s)
                                 (\errs, _ => us () s)
                                 (\errs, _ => cs () s)
                                 s