Haskell монады и сбой, который не требует строки - PullRequest
5 голосов
/ 22 декабря 2011

У меня есть следующий монадный преобразователь для работы с ошибками в 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?

Ответы [ 2 ]

7 голосов
/ 22 декабря 2011

Ну, fail вызывается, если у вас есть ошибка совпадения с образцом в блоке do, например, если у вас есть Just x <- something и результат something равен Nothing.Кроме того, fail - это обычная функция.

Для проблемы с strMsg "foo" = FooError и т. Д. throwError предлагает более приятный интерфейс для вашего варианта использования?

4 голосов
/ 22 декабря 2011

Эта статья может быть полезна: http://blog.ezyang.com/2011/08/8-ways-to-report-errors-in-haskell-revisited/

Ваш EitherT уже находится в стандартной библиотеке и называется ErrorT.См. Документацию: http://hackage.haskell.org/packages/archive/mtl/latest/doc/html/Control-Monad-Error.html#t:ErrorT

fail в настоящее время является историческим курьезом и может рассматриваться как недостаток дизайна, наряду с отсутствием ограничения Functor a => Monad a.Это лишь сомнительная особенность, чтобы справиться не удалось соответствует шаблону в do нотации.

throwError :: MonadError e m => e -> m a

является наиболее распространенной заменой fail, но более доступны (см статью).

...