编辑更完整的问题:
我想创建一个解析器(我正在使用 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 解析器的令人信服的例子,那么你建议的方法是什么?
如果我叫错了树,也请告诉我。