У меня есть следующий монадный преобразователь для работы с ошибками в Haskell.
instance (Monad m, Error e) => Monad (EitherT e m) where
return = EitherT . return . return
m >>= k = EitherT $ do
a <- runEitherT m
case a of
Left l -> return (Left l)
Right r -> runEitherT (k r)
fail = EitherT . return . Left . strMsg
Он работает довольно хорошо, так как я могу создать экземпляр Error
с пользовательским классом и иметь довольно гибкие средства, с помощью которыхобрабатывать ошибки.
fail
немного глупо, хотя, потому что это тип String -> EitherT e m
, а ограничение String
может быть раздражающим способом создания ошибок.В итоге я получаю много:
instance Error BazError where
strMsg "foo" = FooError -- oh look we have no error context
strMsg "bar" = BarError -- isn't that nice
Я хотел бы создать новую функцию, такую как fail
, типа a -> e
, чтобы я мог удалить (Error e)
ограничение.fail
особенно удобно, когда стек монад становится большим, например, когда я получаю
EitherT BazError (StateT [BazWarning] IO) Foo
Есть ли способ создать функцию, которая будет вести себя так же, как fail
, с менее ограниченным типом?Или fail
реализован с использованием глубокой темной магии Haskell?