为什么这个Parsec permutation parser无法解析 b ?
p :: Parser (String, String)
p = permute (pair
<$?> ("", pa)
<|?> ("", pb))
where pair a b = (a, b)
pa :: Parser String
pa = do
char 'x'
many1 (char 'a')
pb :: Parser String
pb = do
many1 (char 'b')
λ> parseTest p "xaabb"
("aa","bb") -- expected result, good
λ> parseTest p "aabb"
("","") -- why "" for b?
解析器pa
通过<$?>
配置为可选,因此我无法理解为什么失败会影响 b 的解析。我可以将其更改为optional (char 'x')
以获得预期的行为,但我不明白为什么。
pa :: Parser String
pa = do
optional (char 'x')
many1 (char 'a')
pb :: Parser String
pb = do
optional (char 'x')
many1 (char 'b')
λ> parseTest p "xaaxbb"
parse error at (line 1, column 2):
unexpected "a"
expecting "b"
λ> parseTest p "xbbxaa"
("aa","bb")
当我们有相同的共享前缀&#34; x&#34;?
时,如何支持两种输入排序?我也不了解可选&#34; x&#34;正在进行解析行为:
pb :: Parser String
pb = do
try px -- with this try x remains unconsumed and "aa" gets parsed
-- without this try x is consumed, but "aa" isn't parsed even though "x" is optional anyway
many1 (char 'b')
px :: Parser Char
px = do
optional (char 'x')
char 'x' <?> "second x"
λ> parseTest p "xaaxbb" -- without try on px
parse error at (line 1, column 2):
unexpected "a"
expecting second x
λ> parseTest p "xaaxbb" -- with try on px
("aa","")
答案 0 :(得分:5)
parseTest p "aabb"
会("","")
排列解析器尝试剥离给定字符串前缀的前面,这些前缀可以由其组成解析器解析(在这种情况下为pa
和pb
)。在这里,它会尝试将pa
和pb
同时应用于"aabb"
,但在两种情况下都失败了 - 它甚至都没有试图解析"bb"
。
pa
和pb
都不能以optional (char 'x')
查看permute
,您会看到它使用的是choice
,而后者依赖于(<|>)
。正如(<|>)
的文档所述,
这个组合器实现了选择。解析器
p <|> q
首先应用p
。如果成功,则返回p
的值。如果p
在没有消耗任何输入的情况下失败,则会尝试解析器q
。此组合定义等于mplus
类的MonadPlus
成员和(<|>)
的{{1}}成员。解析器被称为预测,因为只有当解析器
Alternative
没有消耗任何输入时才会尝试q
(即前瞻是1)。这种非回溯行为既可以有效地实现解析器组合器,也可以生成良好的错误消息。
因此当你执行p
之类的操作时,parseTest p "xbb"
不会立即失败(它消耗并且pa
)然后整个事情都会失败,因为它无法回溯。
正如丹尼尔建议的那样,最好将你的语法分解出来。或者,您可以使用'x'
:
解析器
try
的行为类似于解析器try p
,除了假装它在发生错误时没有消耗任何输入
根据我们之前为p
所讨论的内容,您应该将(<|>)
放在try
的前面。
答案 1 :(得分:2)
为什么这个Parsec排列解析器不解析b?
因为'a'
不是解析器pa
或解析器pb
的有效第一个字符。
当我们有相同的共享前缀&#34; x&#34;?
时,如何支持两种输入排序?
必须从语法中考虑共享前缀;插入回溯点(使用try
),但会牺牲性能。