## Monadic computations

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

## Failable computations. Left absorbing elements

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
```

## Exceptions

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
```

## Throwable errors that cannot escape the monad - ExceptT

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
```

### The Except monad

*(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
```

## Leveraging exceptions into monad errors

```
{-# LANGUAGE PackageImports #-}
import Control.Monad (when)
import "transformers" Control.Monad.Trans.Except
import "exceptions" Control.Monad.Catch
data Err2 = Err2Cons1 String | Err2_Other deriving (Eq, Show)
instance Exception Err2
data Err1 = Err1Cons1 String | Err1Cons2 Err2 deriving (Eq, Show)
-- an exception throwing action
action2 :: IO Int
action2 = do
x <- return someCalculation
when (x `notElem` expectedValues) $ throwM $ Err2Cons1 "Unexpected!"
...
return x
-- an error throwing action
action1 :: ExceptT Err1 IO Int
action1 = do
-- set the condition at will
when condition $ throwE $ Err1Cons1 "err1 msg"
-- wrapping an exception throwing action
withExceptT Err1Cons2 $ ExceptT (try action2)
main :: IO ()
main = do
eRes <- runExceptT action1
case eRes of
Left err1 -> putStrLn $ "error: " ++ show err1
Right v -> putStrLn $ "ok: " ++ show v
```