0

编辑更完整的问题:

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

我现在意识到这一定是一个单子解析器。

我有一个包含非直接左递归的语法。下图说明了问题,实际情况稍微复杂一些:

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,则后过滤器将失败。正如已经正确指出的那样,这是一个单子解析。我找不到任何使用 uu-parsinglib 作为 monadic 解析器的令人信服的例子,那么你建议的方法是什么?

如果我叫错了树,也请告诉我。

4

2 回答 2

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)

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

于 2013-12-04T07:01:44.763 回答
0

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

建议的解决方案是

pA :: Parser A
pA = do
   a <- pField
   case a of 
      (Field_A r) -> return r
      otherwise   -> pFail
于 2013-08-01T10:16:42.427 回答