parsing - 解析器库中的 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”部分。但没有给它这样的机会。
查看for的定义(<|>)
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
等,让我们看看他们对Parser
定义的解释:
前四个参数是行为延续:
epsilon 成功:解析器没有消耗任何输入,并且有结果以及可能的 Err;位置和块不变(见纯)
epsilon failure:解析器没有消耗任何输入,并且由于给定的 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
“已提交失败”而失败。这正是您所观察到的。
推荐阅读
- ms-word - Microsoft Word:当出现特定样式时,如何在边距中插入竖线?
- c++ - 如何通过 C++ 中的另一个类访问类中的数据?
- wpf - MvvmCross 和 Xamarin.Forms.Wpf
- javascript - 有什么方法可以访问在函数中添加了事件侦听器的元素?
- php - 从数据库中提取数据。如何编写循环函数 PHP MYSQL
- sql - 如何计算四分位数范围
- node.js - Discord.js 用于删除所有不是机器人命令的消息
- javascript - Javascript 正则表达式:从多个锚标记中删除除 href 之外的所有属性。不能在正则表达式中包含双引号
- javascript - 如何编号每个
- 在我的
- 或使用项目符号列出它们
- javascript - Javascript Intl.DateTimeFormat hours12 在 Chrome 上给出奇怪的输出