У меня есть следующий монадный преобразователь для работы с ошибками в 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
реализовано с использованием темной магии глубокого хаскеля?
fail
, если только вы не хотите настраивать поведение при неудачных совпадениях с шаблономdo
. - person ehird   schedule 22.12.2011