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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.