concrete functor and monad transformers
#65Add exception handler newtype
catchE
and throwE
make ExceptT
into a monad in the exception type:
newtype HandleExcept a m e = HandleExcept { runHandleExcept :: ExceptT e m a }
instance Functor (HandleExcept a m) where
fmap f = HandleExcept . withExceptT f . runHandleExcept
instance Monad (HandleExcept a m) where
return = HandleExcept . throwE
he >>= f = HandleExcept $ runHandleExcept he `catchE` (runHandleExcept . f)
try :: ExceptT e m a -> HandleExcept a m e
try = HandleExcept
safe :: m a -> HandleExcept a m Void
safe = HandleExcept . lift
safely :: HandleExcept a m Void -> m a
safely = fmap (fromLeft $ error "safely: Got Right value") . runExceptT . runHandleExcept
This monad interface is very useful. We can write programs like this:
finallyCalculateThatValue = safely $ do
reasonItMightNotHaveWorked <- try $ calculateValue
someBackupPlan <- handler reasonItMightNotHaveWorked
safe $ thisWillAlwaysWork someBackupPlan
It will execute all the statements after each other until they throw exceptions (or succeed in returning a value). For example:
rightToMaybe :: ExceptT m a e -> m (Maybe a)
rightToMaybe mae = safely $ do
e <- try mae
safe $ return Nothing
HandleExcept
is also a functor in the category of monads (http://hackage.haskell.org/package/mmorph-1.1.2/docs/Control-Monad-Morph.html#t:MFunctor).