我正在为我的项目编写一个简单文本模板语言的解析器,并且我完全陷入了 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}
^
最佳答案
opt
的文档说:
If p can be recognized, the return value of p is used. Otherwise, the value v is used. Note that opt by default is greedy.
<<|>
的文档中解释了贪婪的含义。 :
<<|> is the greedy version of <|>. If its left hand side parser can make any progress then it commits to that alternative.
在您的情况下,opt
的第一个参数确实识别部分输入,因为 else
和end
两者都以 e
开头。因此,它 promise pElse
,这会失败并导致整个解析失败。
解决这个问题的一个简单方法是使用 ... <|> pure Nothing
,如文档所示。
关于parsing - 在 uu-parsinglib 中使用 `opt` 组合器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9512374/