如何解决解析器库中的try和<|>函数如何工作
(我使用trifecta
解析器库)。我正在尝试制作一个解析器,将整数解析为Right
,并将文字序列(允许使用字母,数字符号和“-”)解析为Left
:
*Lib> parseString myParser mempty "123 qwe 123qwe 123-qwe-"
Success [Right 123,Left "qwe",Left "123qwe",Left "123-qwe-"]
那是我发明的:
myParser :: Parser [Either String Integer]
myParser = sepBy1 (try (Right . read <$> (some digit <* notFollowedBy (choice [letter,char '-'])))
<|> Left <$> some (choice [alphaNum,char '-']))
(char ' ')
我的问题是我不明白为什么在那里需要try
(以及在任何其他类似情况下)。不使用try
时,会出现错误:
*Lib> parseString myParser mempty "123 qwe 123qwe 123-qwe-"
Failure (ErrInfo {_errDoc = (interactive):1:12: error: expected: digit
1 | 123 qwe 123qwe 123-qwe-<EOF>
| ^,_errDeltas = [Columns 11 11]})
因此try
将解析游标放回到失败时开始的地方。想象没有使用try
:
123qwe
^ failed there,the cursor position remains there
另一方面,<|>
就像“两个”之一。它应该运行第二个解析器Left <$> some (choice [alphaNum,char '-']))
(当第一个解析器失败时)并且仅消耗“ qwe”。
在某个地方我错了。
解决方法
如果只有第二个解析器可以运行,它的确会消耗“ qwe”部分。但这没有机会。
查看the definition of (<|>)
中的Parser
:
Parser m <|> Parser n = Parser $ \ eo ee co ce d bs ->
m eo (\e -> n (\a e' -> eo a (e <> e')) (\e' -> ee (e <> e')) co ce d bs) co ce d bs
嗯...看这个可能不是一个好主意。但是,让我们继续前进。为了弄清所有这些eo
,ee
等,让我们看一下它们的解释on the Parser
definition:
前四个参数是行为延续:
ε成功:解析器未消耗任何输入,并且结果以及可能的Err;位置和块保持不变(请参见纯)
ε失败:解析器未消耗任何输入,并且由于给定的Err而失败;位置和块保持不变(请参见空白)
承诺成功:解析器消耗了输入并产生了结果,允许该解析继续的一组预期字符串,新的位置以及继续的剩余块。
已提交失败:解析器消耗了输入并且由于给定的ErrInfo(面向用户的错误消息)而失败
在您的情况下,我们显然有“提交失败”的问题,即Right
解析器消耗了一些输入而失败了。因此,在这种情况下,它将称为第四个延续-在ce
的定义中表示为(<|>)
。
现在看一下定义的主体:第四次延续未更改地传递到解析器m
:
m eo (\e -> n (\a e' -> eo a (e <> e')) (\e' -> ee (e <> e')) co ce d bs) co ce d bs
^
|
here it is
这意味着从(<|>)
返回的解析器将在解析器m
调用的所有情况下调用第四个延续。这意味着在解析器m
因“ committed failure”而失败的所有情况下,它将因“ committed failure”而失败。正是您所观察到的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。