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 (