haskell - 如何在 trifecta 解析器中发出失败信号

标签 haskell trifecta

作为 trifecta 的实验,我编写了以下简单函数:

filterParser :: (a -> Bool) -> Parser a -> Parser a
filterParser cond p = do
  a <- p
  if cond a 
    then return a 
    else unexpected "condition failed!"

这个想法是能够向解析器添加一个条件。例如(假设谓词 prime 已经存在),您可以编写: filterParser prime integer 创建一个只接受素数的解析器。


使用单个解析似乎没问题:

> parseString (filterParser (> 'm') letter) mempty "z"
> Success 'z

> parseString (filterParser (> 'm') letter) mempty "a"
> Failure (interactive):1:2: error: unexpected
> condition failed!

但是对于“很多”它不起作用 - 比较:

> parseString (many $ filterParser (> 'm') letter) mempty "zzz2"
> Success "zzz"

> parseString (many $ filterParser (> 'm') letter) mempty "zzza"
> Failure (interactive):1:5: error: unexpected
> condition failed!

我希望最后一个示例也能返回成功“zzz”。对 unexpected 的调用似乎使整个解析脱轨,这不是我想要的。

最佳答案

您需要使用try使filterParser可恢复:

import Text.Trifecta
import Control.Applicative

filterParser :: (a -> Bool) -> Parser a -> Parser a
filterParser cond p = try $ do
  x <- p
  if cond x then return x else empty

但是,这将消除自定义解析错误。由于 try,在 else 分支中使用意外的“条件失败” 来恢复也没有帮助。

相反,我们可以在 try 之后恢复自定义错误消息:

filterParser :: (a -> Bool) -> Parser a -> Parser a
filterParser cond p = (<|> unexpected "Condition failed") $ try $ do
  x <- p
  if cond x then return x else empty

这按预期工作:

*Main> parseString (many $ filterParser (> 'm') letter) mempty "zzza"
Success "zzz"

*Main> parseString (filterParser (> 'm') letter) mempty "a"
Failure (interactive):1:1: error: unexpected
    Condition failed
a<EOF> 

关于haskell - 如何在 trifecta 解析器中发出失败信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36142078/

相关文章:

parsing - 使用 Trifecta 的布局解析器

haskell - 如何在 IO 中包装单子(monad) Action

haskell - 什么是 Haskell `(->) a` 单子(monad)?

list - 如何计算列表中有多少个元素?

haskell - 一次更新两个记录字段时类型变量不明确(但更新一个记录字段时则不然!)

parsing - 如何在 Haskell 中组合解析器最多 n 次?

regex - 正则表达式的所有匹配的索引

haskell - Haskell 树上折叠的变化

parsing - haskell /三连胜 : Parsing completely optional semicolons without polluting AST