Ответ 1
Библиотека Control.Monad.Exception позволяет использовать строго типизированные исключения для использования в коде, отличном от IO. Это позволяет функциям бросать ошибки и легко компоноваться с функциями, которые вызывают разные ошибки. Например:
{-# LANGUAGE RankNTypes, MultiParamTypeClasses, FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
import Prelude hiding (catch)
import Control.Monad.Exception
data FooException = FooException deriving (Show, Typeable)
instance Exception FooException
data BarErrors = BarErrors deriving (Show, Typeable)
instance Exception BarErrors
data BazErrors = BazErrors deriving (Show, Typeable)
instance Exception BazErrors
-- sample functions
foo :: (Throws FooException l) => a -> EM l a
foo a = return a
bar :: (Throws BarErrors l) => a -> EM l a
bar _ = throw BarErrors
baz :: (Throws BazErrors l) => a -> EM l a
baz a = return a
-- using all at once:
allAtOnce :: (Throws FooException l, Throws BarErrors l, Throws BazErrors l) =>
a -> EM l String
allAtOnce x = do
_ <- foo x
_ <- bar x
_ <- baz x
return "success!"
-- now running the code, catching the exceptions:
run :: a -> String
run x = runEM $ allAtOnce x `catch` (\(_ :: FooException) -> return "foo failed")
`catch` (\BarErrors -> return "bar failed")
`catch` (\BazErrors -> return "baz failed")
-- run 3 results in "bar failed"
См. также статьи Явно типизированные исключения для Haskell и Расширяемая динамически типизированная иерархия исключений для более подробную информацию об использовании этой библиотеки.