Let ReadP carry a failure message
Dannyu NDos
ndospark320 at gmail.com
Fri Nov 20 03:08:00 UTC 2020
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.
More information about the Libraries
mailing list