Imagine the following example
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
Is there a way to implement such logic where I can try to use a parser, and if it is successful do some transformation on the result, and otherwise use another parser? I know this particular example could be written such as the following
parseC = (convertA <$> parseA) <|> parseB
but is there a more general way to represent this pattern in the monadic notation?
You can represent it more monadically, but I don't know if I'd call it a more general pattern.
Normally, success or failure of a parser is handled implicitly through the MonadPlus
and Alternative
interfaces. However, you can reify success/failure and operate on it in the Monad
context if you really want to. The function to do that reification is optionMaybe
in Text.Parsec.Combinator.
parseC :: Parser C
parseC = do
ma <- optionMaybe parseA
case ma of
Just a -> return $ convertA a
Nothing -> parseB
One important note here is that optionMaybe
is.. special. It only succeeds with a Nothing
result in the case when the parser provided to it fails without consuming input. Of course your example code is broken anyway if parseA
can consume input while failing, so I assume you're familiar with that issue. This brokenness is why I hate parsec and will never use it in my own code, by the way. Sorry for the editorializing, I just don't think that issue is something every user should be forced to stumble over.