作为三连胜的实验,我写了以下简单的函数:
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!
我希望最后一个例子也会返回Success "zzz"
。对unexpected
的调用似乎会破坏整个解析,这不是我想要的。
答案 0 :(得分:1)
您需要使用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
然而,这将摆脱自定义解析错误。由于unexpected "Condition failed"
,使用else
分支中的try
进行恢复并不会有所帮助。
相反,我们可以在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>
答案 1 :(得分:1)
除了Cactus建议的解决方案之外,还有以下内容:
filterParser :: (a -> Bool) -> Parser a -> Parser a
filterParser cond p = do
a <- lookAhead p
if cond a then p else unexpected "condition failed!"
这似乎给了我想要的东西:
> parseString (filterParser (> 'm') letter) mempty "z"
> Success 'z'
> parseString (filterParser (> 'm') letter) mempty "4"
> Failure (interactive):1:1: error: expected: letter
> parseString (filterParser (> 'm') letter) mempty "a"
> Failure (interactive):1:1: error: unexpected
> condition failed!
> parseString (many $ filterParser (> 'm') letter) mempty "zzz4"
> Success "zzz"
> parseString (many $ filterParser (> 'm') letter) mempty "zzza"
> Success "zzz"