如何使用parsec进行条件monadic解析?

Jak*_*old 3 parsing haskell parsec

想象一下下面的例子

data A = ...
data B = ...
data C = ...

convertA :: A -> C

parseA :: Parser A
parseB :: Parser B

parseC :: Parser C
parseC = do
  a <- parseA
  if parsed? a
    then return $ convertA a
    else parseB
Run Code Online (Sandbox Code Playgroud)

有没有办法实现这样的逻辑,我可以尝试使用解析器,如果成功,对结果进行一些转换,否则使用另一个解析器?我知道这个特殊的例子可以写成如下

parseC = (convertA <$> parseA) <|> parseB
Run Code Online (Sandbox Code Playgroud)

但是有一种更通用的方式来表示这种模式的monadic符号吗?

Car*_*arl 8

你可以用monadically代表它,但我不知道我是否称它为更通用的模式.

通常,解析器的成功或失败是通过MonadPlus和Alternative接口隐式处理的.但是,Monad如果您真的想要,可以在上下文中重新确定成功/失败并对其进行操作.执行该具体化的功能optionMaybe在Text.Parsec.Combinator中.

parseC :: Parser C
parseC = do
    ma <- optionMaybe parseA
    case ma of
        Just a -> return $ convertA a
        Nothing -> parseB
Run Code Online (Sandbox Code Playgroud)

这里有一个重要的注意事项optionMaybe是..特别的.只有Nothing在提供给它的解析器失败而不消耗输入的情况下,它才会成功.当然,如果parseA在失败时消耗输入,你的示例代码仍会被破坏,所以我假设你已经熟悉了这个问题.这种破坏是我讨厌parsec并且永远不会在我自己的代码中使用它的原因.对于编辑抱歉,我只是不认为这个问题是每个用户都应该被迫绊倒的问题.