
Firstly, I propose a new class. This class is like MonadFail, but with "error bind" operator: class Monad m => FailMsg m where failMsg :: String -> m a (>?=) :: m a -> (String -> m a) -> m a Laws are: * For every (x :: m a), if (x ≡ fail msg) for some (msg :: String), msg shall be unique. * For (x ≡ fail msg), (x >?= f ≡ f msg). If such msg doesn't exist, (x >?= _ ≡ x). Basic instances are: instance e ~ String => FailMsg (Either e) where failMsg = Left Left msg >?= f = f msg x >?= _ = x instance FailMsg IO where failMsg = throwIO . userError action >?= f = catch action (f . ioeGetErrorString) Now let's focus on ReadP. Let P carry a failure message: data P a = Get (Char -> P a) | Look (String -> P a) | Fail String | Result a (P a) | Final (NonEmpty (a,String)) Then we have: instance FailMsg P where fail = Fail Fail msg >?= f = f msg p >?= _ = p instance FailMsg ReadP where fail msg = R (\_ -> fail msg) R m >?= f = R (\k -> case m k of Fail msg -> let R n = f msg in n k p -> p ) This is incredibly useful. This can be used when there are multiple types of parse error.