我刚开始学习使用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")
输出:
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"
当第二个<|>
的左侧部分失败时,始终的正确方法是什么?我可以覆盖之前发生的任何错误吗?
答案 0 :(得分:8)
Parsec中的<|>
组合子仅在解析器不使用任何输入时尝试下一个选项。在您的情况下,解析器string "456"
与"45x"
的开头匹配,因此不再尝试其他替代方法。如果您需要任意预测,则需要使用try
函数。
ps :: Parser String
ps = string "123" <|> try (string "456") <|> fail "my-failure"
来自Parsec的<|>
文档:
这个组合器实现了选择。解析器p&lt; |&gt;首先应用p。如果成功,则返回p的值。如果p在没有消耗任何输入的情况下失败,则尝试解析器q。该组合子的定义等于MonadPlus类的mplus成员和Alternative的(&lt; |&gt;)成员。
解析器被称为预测,因为q仅在解析器p时尝试 不消耗任何输入(即......前瞻是1)。这个 非回溯行为允许有效的实现 解析器组合器的组合以及良好错误消息的生成。