Search code examples
parsinghaskellparsec

Creating a parser combinator of type Parser a -> Parser b -> Parser (Either a b)


I want to parse some text in which certain fields have structure most of the time but occasionally (due to special casing, typos etc) this structure is missing.

E.g. Regular case is Cost: 5, but occasionally it will read Cost: 5m or Cost: 3 + 1 per ally, or some other random stuff.

In the case of the normal parser (p) not working, I'd like to fallback to a parser which just takes the whole line as a string.

To this end, I'd like to create a combinator of type Parser a -> Parser b -> Either a b. However, I cannot work out how to inspect the results of attempting to see if the first parser succeeds or not, without doing something like case parse p "" txt of ....

I can't see a build in combinator, but I'm sure there's some easy way to solve this that I'm missing


Solution

  • I think you want something like this

    eitherParse :: Parser a -> Parser b -> Parser (Either a b)
    eitherParse a b = fmap Left (try a) <|> fmap Right b
    

    The try is just to ensure that if a consumes some input and then fails, you'll backtrack properly. Then you can just use the normal methods for running a parser to yield Either ParseError (Either a b)

    Which is quite easy to transform into your Either a b

    case parse p "" str of
      Right  (Left a) -> useA a
      Right (Right b) -> useB b
      Left   err      -> handleParserError err