0

我刚刚开始学习使用 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"

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

4

1 回答 1

9

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

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

来自 Parsec 的文档<|>

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

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

于 2013-03-13T07:47:11.087 回答