在uu-parsinglib中使用`opt`组合子

时间:2012-03-01 07:41:50

标签: parsing haskell

我正在为我的项目编写一个简单文本模板语言的解析器,我完全停留在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}
                              ^

1 个答案:

答案 0 :(得分:2)

opt的文档说:

  

如果可以识别p,则使用p的返回值。否则,使用值v。请注意,默认情况下,opt是贪婪的。

<<|>的文档中解释了贪婪的含义:

  

&LT;&LT; |&GT;是&lt; |&gt;的贪婪版本。如果它的左侧解析器可以取得任何进展,那么它就会提交给那个替代方案。

在您的情况下,opt的第一个参数确实识别输入的一部分,因为elseend都以e开头。因此,它提交到pElse,它失败并使整个解析失败。

解决此问题的一种简单方法是使用... <|> pure Nothing,如文档所示。