我可以轻松地将 attoparsec 包装在变压器中吗?
Can I easily wrap attoparsec in transformer?
我想编写代码来执行 C 预处理之类的操作。所以我找了图书馆,找到了两个候选人,attoparsec
、megaparsec
.
我需要报告错误位置的功能,megaparsec
已经有了。但是 attoparsec
对性能来说是可取的。
如果我将错误位置功能添加到 attoparsec
的 Parser
monad,那么我是否必须将其包装在 StateT
转换器中并在我执行时提升所有库的功能使用它们?我认为这是一项令人厌烦的工作。有没有更好的方法?
编辑
我会采用适合这种情况的megaparsec
。但我仍然想知道如何包装 attoparsec
的 Parser
monad。有没有人可以告诉我我上面提到的方法是否是最好的方法?
我只想知道 monad 包装方法。换句话说,提升所有内部monad功能是否是唯一的解决方案。
您可以从 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)
,而是偏移量
足以满足许多应用。
使用fromPos
从Pos
得到Int
:
λ> 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"
最后一点:如果你真的需要一个转换器并且想继续使用 attoparsec 包,Data.Attoparsec.Zepto
确实提供了 ZeptoT
转换器,但是这个是与 attoparsec.
中的主解析器不同的解析器类型
我想编写代码来执行 C 预处理之类的操作。所以我找了图书馆,找到了两个候选人,attoparsec
、megaparsec
.
我需要报告错误位置的功能,megaparsec
已经有了。但是 attoparsec
对性能来说是可取的。
如果我将错误位置功能添加到 attoparsec
的 Parser
monad,那么我是否必须将其包装在 StateT
转换器中并在我执行时提升所有库的功能使用它们?我认为这是一项令人厌烦的工作。有没有更好的方法?
编辑
我会采用适合这种情况的megaparsec
。但我仍然想知道如何包装 attoparsec
的 Parser
monad。有没有人可以告诉我我上面提到的方法是否是最好的方法?
我只想知道 monad 包装方法。换句话说,提升所有内部monad功能是否是唯一的解决方案。
您可以从 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)
,而是偏移量
足以满足许多应用。
使用fromPos
从Pos
得到Int
:
λ> 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"
最后一点:如果你真的需要一个转换器并且想继续使用 attoparsec 包,Data.Attoparsec.Zepto
确实提供了 ZeptoT
转换器,但是这个是与 attoparsec.