3
votes

Parsec provides an operator to choose between two parsers:

(<|>)
  :: Text.Parsec.Prim.ParsecT s u m a
     -> Text.Parsec.Prim.ParsecT s u m a
     -> Text.Parsec.Prim.ParsecT s u m a

Is there a similar function to chain two parsers? I didn't find one with the same signature using Hoogle.


As an example, let's say I want to parse any word optionally followed by a single digit. My first idea was to use >> but it doesn't seem to work.

parser = many1 letter >> optional (fmap pure digit)

I used fmap pure in order to convert the digit to an actual string and thus match the parsed type of many1 letter. I don't know if it is useful.

1
>> or *> do sequence parsers, through their Monad/Applicative instances, but they only return the result of the second parser. (Likewise, <* returns the result of the first; and as a convenience, x <$ p returns a constant value x, equivalent to the common pattern p *> pure x). You don’t strictly need the fmap pure there, since the result types don’t need to match, but it may often be more convenient to combine results using <$> and <*> (as in @SergeyKuz1001’s answer) if the types are the same.Jon Purdy
It's a very clear explanation, thank you!Gulliver

1 Answers

4
votes

Try this:

parser = (++) <$> many1 letter <*> option "" (fmap pure digit)

This is equivalent to:

parser = pure (++) <*> many1 letter <*> option "" (fmap pure digit)

option [] (fmap pure digit) return empty string if the parser digit have failed and a string from one digital char otherwise.

You can also use do-notation for more readable code:

parser = do
    s1 <- many1 letter
    s2 <- option "" (fmap pure digit)
    return (s1 ++ s2)