使用 ParsecT 进行排列解析?

Permutation parsing with `ParsecT`?

我有一个文件解析器,它使用 parsec 中的 permute 来组合各种 Parser。看起来 permute 只允许 Identity monad,我确信这会降低算法的复杂性。

现在我正在尝试将我所有的解析代码转换为使用 MyErrorClass m => ParsecT String () m,其中 Monad m => MyErrorClass m 是具有特殊错误处理的 class。具体来说,使用 permute 的代码现在需要组合需要 MyErrorClass m 的解析器,以便它们可以提供结构化错误,而不仅仅是使用 fail。 (permute 仅在解析编程语言的模块配置文件时使用。文件格式允许嵌入某些语言结构,重用编译器的解析器。)

我只在 3 个地方使用 permute,而且这个数字不太可能增加,所以为这 3 个中的每一个拼凑出某种一次性函数并不是不可能的. 或者,我可以删除字段排序的灵活性,但我宁愿不这样做。


在我做任何重要的事情之前,我是否缺少 parsec 中的简单解决方案?也许我可以以某种方式将 ParsecT String () mparsers 填充到 permute 而不是 parsec? (这会增加依赖性,但可能是值得的。)


编辑:

以下是有关为什么结构化错误对解析有用的一些背景知识。

在大多数情况下,我分别进行解析和验证。例如,在解析成功后检查重复的符号定义。

我经常遇到类似于 expected //, /* or argument type 的解析错误,可能需要一段时间(对我来说,语言创建者)才能理解正在调用的解析器。

MyErrorClass 允许结构化错误消息,例如

("In parsing of function declaration for " ++ show f) ??> do
  -- parse the components of function f
  -- any error messages here will be nested under the message above

能够像这样添加上下文至少会告诉用户解析器在失败时试图做什么。

最后,使用 MyErrorClass 也将允许 try<|> 无法抑制的快速失败错误。 (在一些地方,我有使用过时语法的明确错误消息。)

正如@danidiaz 所建议的,parser-combinators 轻松解决了 文字 置换 ParsecT.

的问题

需要注意的是,将 ParsecTMonad m 一起使用 转换 错误(甚至它自己的错误)并不是特别有用,除了能够使用 <|>try.

无法忽略的快​​速失败错误
  • 您不能将 ParsecT 的错误状态“降级”为 m 自己的错误类型,因为(据我所知)无法访问ParsecT.

    的当前错误状态
  • ParsecT 缺少与 StateTmapStateT 相媲美的东西。这意味着如果不使用 runPT(等)实际执行解析器,就无法转换存储在 m 中的错误,这是不可能进行中间解析的。

总而言之,ParsecT 不会像 StateT 那样泄露 m,从而导致 m 的某些功能无法从 ParsecT.