Hi,
when thinking about this SO question, I couldn't find a combinator that allows a parser to optionally fail without consuming input, or consume input and return its value. So I'm suggesting such a function:
-- | @emptyIf p@ parses @p@ and if its return value is @Nothing@, pretends
-- that an error has occured with no input consumed.
--
-- If @p@ fails and consumes some input, so does @emptyIf p@. Combine with
-- 'try' if this is undesirable.
emptyIf :: (Stream s m t) => ParsecT s u m (Maybe a) -> ParsecT s u m a
emptyIf p = ParsecT $ \s cok cerr eok eerr ->
let cok' (Just x) s e = cok x s e
cok' Nothing _ e = eerr e
eok' (Just x) s e = eok x s e
eok' Nothing _ e = eerr e
in unParser p s cok' cerr eok' eerr
With this function, the answer to the SO question becomes really easy:
rcomb :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
rcomb p q = emptyIf $ runMaybeT (opt p *> opt q)
where
opt = MaybeT . optional -- optional from Control.Applicative!
Whenever p
or
q
fails without consuming input, then rcomb p q
fails without consuming input.
Unfortunately ParsecT
constructor isn‘t exported so I’m not able to implement it
outside parsec. (Perhaps it would make sense to export
ParsecT
in some module such as Text.Parsec.Internal
?)
Therefore I'm suggesting to add such a function to parsec
(darcs patch included). Perhaps change the name, I couldn't
think of anything better.
Best regards,
Petr