我正在为我的项目编写一个简单的文本模板语言的解析器,我完全被uu-parsinglib中的opt组合子所困扰(如果有必要的话,2.7.3.2版本)。有关于如何正确使用它的想法吗?
这是一个非常简单的例子,它显示了我的困境。
{-# LANGUAGE FlexibleContexts #-}
import Text.ParserCombinators.UU hiding (pEnd)
import Text.ParserCombinators.UU.Utils
import Text.ParserCombinators.UU.BasicInstances
pIdentifier :: Parser String
pIdentifier = pMany pLetter
pIfClause :: Parser ((String, String), String, Maybe (String, String), String)
pIfClause = (,,,) <$> pIf <*> pIdentifier <*> pOptionalElse <*> pEnd
pIf :: Parser (String, String)
pIf = pBraces ((,) <$> pToken "if " <*> pIdentifier)
pOptionalElse :: Parser (Maybe (String, String))
pOptionalElse = (((\x y -> Just (x, y)) <$> pElse <*> pIdentifier) `opt` Nothing)
pElse :: Parser String
pElse = pBraces (pToken "else")
pEnd :: Parser String
pEnd = pBraces (pToken "end")
main :: IO ()
main = do
putStrLn $ show $ runParser "works" pIfClause "{if abc}def{else}ghi{end}"
putStrLn $ show $ runParser "doesn't work" pIfClause "{if abc}def{end}"第一个字符串可以正确解析,但第二个字符串会失败,并显示错误:
main: Failed parsing 'doesn't work' :
Expected at position LineColPos 0 12 12 expecting one of [Whitespace, "else"] at LineColPos 0 12 12 :
v
{if abc}def{end}
^发布于 2012-03-01 17:14:08
opt的文档中写道:
如果p可以识别,则使用p的返回值。否则,将使用值v。请注意,默认情况下,opt是贪婪的。
<<|>的文档中解释了贪婪的含义
<<|>是<|>的贪婪版本。如果它的左侧解析器可以取得任何进展,那么它将提交到该替代方案。
在本例中,opt的第一个参数可以识别输入的一部分,因为else和end都以e开头。因此,它提交给pElse,这会导致失败,并导致整个解析失败。
解决此问题的一个简单方法是使用... <|> pure Nothing,正如文档所建议的那样。
https://stackoverflow.com/questions/9512374
复制相似问题