A Monad is an abstract data type for modelling the sequentiality of side effect capable computations that return a result value.

class Monad m where -- return: generates a simple computation with the parameter as result return :: a -> m a -- (>>=) binds a monadic action with a monadic function on its result (>>=) :: m a -> (a -> m b) -> m b -- (>>) binds with a second computation ignoring the result of the first one (>>) :: m a -> m b -> m b x >> y = x >>= \_ -> y -- (>>) can be defined in terms of (>>=) ...

The actual definition extends the Applicative typeclass (sequencing computations while combining its results) with return = pure and (>>) = (*>) , but I want to base this guide on Monads.

The Do block is a syntax construction that translates to a Monadic composition of computations. See do notation

A failable monad domain is one that has a left absorbing element in (>>=) , meaning the monad composition result will be the left operand's one, stopping the evaluation of subsequent computations.

In the Either monad all the values constructed with Left are left absorbing. See Data.Either source

instance Monad (Either e) where Left e >>= _ = Left e -- left absorbing, subsequent comp. are ignored Right x >>= f = f x return = Right

The package exceptions generalizes the exception context to more monads than IO. See Control.Monad.Catch

-- from Control.Monad.Catch class Monad m => MonadThrow m where throwM :: Exception e => e -> m a class MonadThrow m => MonadCatch m where catch :: Exception e => m a -> (e -> m a) -> m a -- MonadCatch instances should obey the following law: catch (throwM e) f ≡ f e

You may forget catching exceptions, that finally crash your application.

{-# LANGUAGE PackageImports #-} import "exceptions" Control.Monad.Catch (MonadThrow(..), MonadCatch(..), try) data MyException = MyExcCase1 String | MyExcCase2 deriving (Eq, Show) instance Exception MyException -- makes an Exception instance action1 :: MonadThrow m => m Int action1 = do ... when condition $ throwM $ MyExcCase1 "message" -- try :: (MonadCatch m, Exception e) => m a -> m (Either e a) action2A :: (MonadCatch m) => m (Either MyException Int) action2A = do ... try action1 -- catches exception that returns as an Either -- forgetting to catch your exceptions action2B :: (MonadCatch m) => m Int acrion2B = do ... action1 -- it may crash if exception not catched in the code upwards ...

See also Catching all exceptions although it is about problems with asynchronous exceptions.

-- exception pkg replacement as recommended in "Catching all exceptions" -- import "exceptions" Control.Monad.Catch import "safe-exceptions" Control.Exception.Safe

ExceptT is a monad transformer that parameterises computations with the error type.

Because the main function must have type IO a , you will have to unwrap your ExceptT transformer (with runExceptT) at some point, and your thrown error will not escape the transformed monad!!, giving you an Either error result to analyze, unlike non-caught exceptions.

-- The ExceptT monad transformer newtype ExceptT err m a = ExceptT (m (Either err a)) -- ^ err: the error type -- ^ m: the inner monad -- the ExceptT unwrapper runExceptT :: ExceptT err m a -> m (Either err a) throwE :: (Monad m) => err -> ExceptT err m a throwE = ExceptT . return . Left catchE :: (Monad m) => ExceptT err m a -- ^ the inner computation -> (err -> ExceptT err' m a) -- ^ a handler for exceptions in the inner -- computation -> ExceptT err' m a catchE m handler = ExceptT $ do a <- runExceptT m case a of Left err -> runExceptT (handler err) Right r -> return (Right r) -- `withExceptT` evaluates a monadic action of a different error type, -- lifting the error to the present action error type, as shown below withExceptT :: Functor m => (e -> e') -> ExceptT e m a -> ExceptT e' m a

(Except err) is a wrapper for failable functional computations in the Identity monad

-- Identity is the identity monad from "base" Data.Functor.Identity type Except err :: * -> * = ExceptT e Identity -- the wrapper except :: Either err a -> Except err a except = Identity >>> ExceptT -- the unwrapper runExcept :: Except err a -> Either err a runExcept = runExceptT >>> runIdentity

Example of use: Simple nesting of error throwing actions. The error type of the outer action is a discriminated union (sum type) of own and child actions errors. I don't use the type alias Except to put emphasis on ExceptT

import "transformers" Control.Monad.Trans.Except import Control.Monad (when) import Data.Functor.Identity -- this would not be necessary using the type alias Except data Err2 = Err2Cons1 String | Err2_Other deriving (Eq, Show) data Err1 = Err1Cons1 String | Err1Cons2 Err2 deriving (Eq, Show) -- throwing an error bypasses the rest of the computation action3 :: ExceptT Err2 Identity Int action3 = do x <- return someCalculation when (x `notElem` expectedValues) $ throwE $ Err2Cons1 "Unexpected!" when condition2 $ throwE Err2_Other return x action2 :: ExceptT Err2 Identity Int action2 = catchE action3 $ \err -> case err of Err2Cons1 msg -> return 0 Err2_Other -> throwE err -- rethrow action1 :: ExceptT Err1 Identity Int action1 = do when condition $ throwE $ Err1Cons1 "err1 msg" withExceptT Err1Cons2 action2 -- evaluates action2 lifting the Err2 type to an Err1 main :: IO () main = do let eRes = runExcept action1 case eRes of Left err1 -> putStrLn $ "error: " ++ show err1 Right v -> putStrLn $ "ok: " ++ show v