Монады Haskell и ошибка, не требующая строки

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


person So8res    schedule 22.12.2011    source источник
comment
Вероятно, вам следует просто полностью избегать fail, если только вы не хотите настраивать поведение при неудачных совпадениях с шаблоном do.   -  person ehird    schedule 22.12.2011


Ответы (2)


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

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

person Daniel Fischer    schedule 22.12.2011

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

Ваш BothT уже находится в стандартной библиотеке и называется 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, но доступны и другие (см. статью).

person nponeccop    schedule 22.12.2011