我可以轻松地将attoparsec包裹在变压器中吗?

时间:2017-01-30 15:34:07

标签: haskell monad-transformers parser-combinators attoparsec megaparsec

我想编写像C预处理这样的代码。所以我找了两个候选人,attoparsecmegaparsec

我需要功能报告错误位置,megaparsec已经有了。但attoparsec对于表现来说是理想的。

如果我将错误位置功能添加到attoparsec的{​​{1}} monad,那么我是否应该将其包含在Parser变压器中,然后解除所有库#39 ;当我使用它们时的功能?我认为这是一项令人厌倦的工作。有没有更好的方法?

修改

我会采用适合这种情况的StateT。但我仍然想知道如何包装megaparsec attoparsec monad。有没有人可以告诉我上面提到的方法是否是最好的方法?

我想知道monad包装方法。换句话说,是否解除所有内部monad函数是唯一的解决方案。

1 个答案:

答案 0 :(得分:2)

您可以从 attoparsec 获取当前的解析位置,而无需变换器。但是没有出口功能可以做到这一点;你必须自己定义:

import qualified Data.Attoparsec.Internal.Types as T

offset :: T.Parser i T.Pos
offset = T.Parser $ \t pos more lose succ -> succ t pos more pos

使用示例:

λ> parseOnly (many' (skipMany (word8 46) *> offset <* anyWord8)) ".a..a...a....a"
Right [Pos {fromPos = 1},Pos {fromPos = 4},Pos {fromPos = 8},Pos {fromPos = 13}]

这也适用于增量输入。它只给你 输入的偏移量,不是(line, column),而是偏移量 足以满足许多应用。

使用fromPosInt

获取Pos
λ> T.fromPos <$> parseOnly offset ""
Right 0

现在,我们可以使用offset创建一个报告当前的解析器 失败时的偏移。

reportOffsetOnError :: T.Parser i a -> T.Parser i a
reportOffsetOnError p =
  p <|> (offset >>= \pos ->
    fail ("failed at offset: " ++ show (T.fromPos pos)))

使用示例:

λ> parseOnly (word8 46 *> word8 46 *> reportOffsetOnError (word8 97)) "..a"
Right 97
λ> parseOnly (word8 46 *> word8 46 *> reportOffsetOnError (word8 97)) "..b"
Left "Failed reading: failed at offset: 2"

最后一点:Data.Attoparsec.Zepto确实提供了ZeptoT变换器,如果你真的需要一个变换器并想继续使用 attoparsec 包,但这是一个不同的解析器类型来自 attoparsec 中的主解析器。