Parsec解析器:在某些条件下不评估自定义失败

Pha*_*rae 0 haskell parsec

我刚刚开始学习使用Parsec解析字符串,我遇到了以下问题,我无法解决这个问题:

以下代码包含三个解析器运行,其中两个显然会失败.奇怪的是,我的自定义失败消息只会在第二次运行时发生,而不是在第三次运行时发生.

import Text.Parsec
import Text.Parsec.String

ps :: Parser String
ps = (string "123") <|> (string "456") <|> fail "my-failure"

main = do
     putStrLn $ "A: " ++ show (parse ps "" "123")
     putStrLn $ "\nB: " ++ show (parse ps "" "789")
     putStrLn $ "\nC: " ++ show (parse ps "" "45x")
Run Code Online (Sandbox Code Playgroud)

输出:

A: Right "123"

B: Left (line 1, column 1):
unexpected "7"
expecting "123" or "456"
my-failure

C: Left (line 1, column 1):
unexpected "x"
expecting "456"
Run Code Online (Sandbox Code Playgroud)

当第二个部分离开时,始终出现失败消息的正确方法是<|>什么?我可以覆盖之前发生的任何错误吗?

sha*_*ang 8

<|>当解析器不使用任何输入时,Parsec中的组合器仅尝试下一个选项.在您的情况下,解析器string "456"匹配开头"45x",因此不再尝试其他替代方法.如果您需要任意预测,则需要使用该try功能.

ps :: Parser String
ps = string "123" <|> try (string "456") <|> fail "my-failure"
Run Code Online (Sandbox Code Playgroud)

来自Parsec的文档<|>:

该组合器实现了选择.解析器p <|> q首先应用p.如果成功,则返回p的值.如果p在没有消耗任何输入的情况下失败,则尝试解析器q.该组合子的定义等于MonadPlus类的mplus成员和Alternative的(<|>)成员.

解析器被称为预测,因为仅在解析器p不消耗任何输入时才尝试q(即,前瞻为1).这种非回溯行为允许解析器组合器的有效实现和良好错误消息的生成.

  • 而不是"<|>失败"我的失败"`你可能更喜欢使用[`<?>`](http://hackage.haskell.org/packages/archive/parsec/latest/doc/html/Text- Parsec-Prim.html #v:-60--63--62-)与`<?>"语法元素"`一样,它将产生错误消息`expecting syntax element`而不是`my-failure`.但你仍然需要使用`try`. (2认同)