为什么此解析器失败以及如何解决?
λ> str1 = string "elif "
λ> str2 = string "else "
λ> strs = (,) <$> many str1 <*> optionMaybe str2
λ> parse strs "" "elif elif elif else "
Left (line 1, column 16):
unexpected "s"
expecting "elif "
如何组合many
解析器和optionalMaybe
解析器?
问题是,string "elif "
会吃掉el
中的else
,并且由于它已经消耗了输入,因此不会回溯,而会抱怨意外的s
最简单的解决方法是允许使用try
进行回溯:
str1 = try $ string "elif "
另一个答案显示了使用try
的简单解决方法。但是,这的确增加了成本,即引入了回溯。在此答案中,我介绍了没有回溯的另一种解决方案,因此,该解决方案应该更快一些并且使用更少的内存。基本思想是解析共享前缀,然后在我们碰到两件事实际上有所不同的部分时调度。因此:
strs = (string "el" *> (elseParser <|> elifParser)) <|> pure ([], Nothing) where
elseParser = ([], Just "else ") <$ string "se "
elifParser = liftA2
(\_ (elifs, elses) -> ("elif ":elifs, elses))
(string "if ")
strs
为简单起见,我在结果中使用了恒定的"else "
和"elif "
字符串,但这些字符串可以由string
解析器的部分结果构建而成,并需要额外的布线。