uu-parsinglib解析条件失败

时间:2013-08-01 08:07:49

标签: parsing haskell applicative

已修改以获得更完整的问题:

我想创建一个解析器(我正在使用uu-parsinglib),它获取前一个解析器的结果,如果结果包含某个构造函数,则有条件地失败:

我现在意识到这必须是一个monadic解析器。

我的语法包含非直接左递归。下面说明了问题,现实情况稍微复杂一点:

data Field = 
       Field_A  A
       Field_B  B
       Field_C  C
       Field_D  String

data A =
       A Prefix String

data B =
       B Prefix String

data C =
       C Prefix String

data Prefix = 
       Prefix Field

大多数时候我只对Field感兴趣,并且为了尽量减少回溯,最好关注这种情况。

我已经定义了一个帮助

的运算符
(<..>) :: IsParser p => p (a -> b) -> p (b -> c) -> p (a -> c)
g <..> f = (.) <$> f <*> g

我将问题解决为:

pField :: Parser Field 
pField =  
   ( Field_D <$> pString ) <??>
   pChainl' ( pReturn (helper) <*> pPrefix' ) ( pA' <<|> pB' <<|> pC' )
   where pChainl' :: IsParser p =>  p (f -> (pre -> f) -> f) -> 
                                       p (pre -> f) -> 
                                       p (f -> f)
         pChainl' op x = must_be_non_empties "pChainl'" op x (
                            flip f <$> pList1 (flip <$> op <*> x)
                         )
         f x [] = x
         f x (func:rest) = f (func x) rest
         helper :: (Field -> Prefix) -> 
                      Field -> 
                      (Prefix -> Field) -> 
                      Field
         helper p i n = n $ p i

注意我已经定义了一个pChainl的变体,它允许传入初始字段,同时保持左关联。

pA' :: Parser (Prefix -> Field)
pA' = ( (flip A) <$> pString ) <..> pReturn Field_A

pB' :: Parser (Prefix -> Field)
pB' = ( (flip B) <$> pString ) <..> pReturn Field_B

pC' :: Parser (Prefix -> Field)
pC' = ( (flip C) <$> pString ) <..> pReturn Field_C

-- This consumes no input
pPrefix' :: Parser (Field -> Prefix)
pPrefix' = pReturn Prefix

问题 我想定义

pA :: Parser A

就pField而言,如果最右边的Field构造函数不是Field_A,则后置过滤器会失败。正如已经正确指出的那样,这是一个monadic解析。我找不到任何使用uu-parsinglib作为monadic解析器的令人信服的例子,那么你建议的方法是什么?

如果我正在咆哮错误的树,请告诉我。

2 个答案:

答案 0 :(得分:1)

似乎你可以创建一个通用的条件解析器,只有在解析器返回的值通过一些测试时才会成功。这当然使用monad功能。我不确定这是否与uu-parsinglib有关。它似乎在我的测试中工作正常,但有一个例外:当条件失败并且没有其他解析器可用于消耗输入时,库会抛出异常。 (没有给出纠正步骤的内容......)

pConditional :: Parser a -> (a -> Bool) -> Parser a
pConditional p test = p >>= (\result -> case (test result) of
    True -> pure result
    False -> empty)

我还想知道自由使用这种条件解析器会产生的其他陷阱。 (如果有的话。)

答案 1 :(得分:0)

我想我找到了解决方案。我仍然有兴趣听取关于解析这种间接左递归的最佳方法的想法。

建议的解决方案是

pA :: Parser A
pA = do
   a <- pField
   case a of 
      (Field_A r) -> return r
      otherwise   -> pFail