Search code examples
haskellparsec

How to form an OR choice in Parsec that may match many options, but must match at least one option?


I'm trying to write a parser in Haskell using the Parsec package. One part of the rules for the input requires the parser to match an option of rules. Out of the rules more than one rule may be match, but at least one rule must match or the parser is expected to produce an error.

Let me provide an example. Assume we have two Parsec rules named first and more. It is possible that:

  • the input matches first followed by more;
  • the input matches only first; or that
  • the input matches only more.

In any case, at least one of first or more must match. Any ideas on how to do this? I thought about using the <|> but if I understand it correctly it will only match one of the rules (i.e. the first one that is successful).

EDIT:

Clarification: If both first and more matches, the result of both must be returned. If only one matches, the returned value of the other can be some null value like Nothing, but it is not allowed to return Nothing for both first and more.


Solution

  • Assuming the things should come is some particular order:

    atLeastOne :: [Parser a] -> Parser [a]
    atLeastOne ps = do
      rs <- catMaybes <$> mapM optionMaybe ps
      if null rs
        then parserFail "At least one thing should be present"
        else return rs