Copyright | (c) Dennis Gosnell 2016 |
---|---|

License | BSD-style (see LICENSE file) |

Maintainer | cdep.illabout@gmail.com |

Stability | experimental |

Portability | POSIX |

Safe Haskell | Safe |

Language | Haskell2010 |

## Synopsis

- fromEitherM :: Applicative m => (e -> m a) -> Either e a -> m a
- fromEitherOrM :: Applicative m => Either e a -> (e -> m a) -> m a
- fromEitherM_ :: (Applicative m, Monoid b) => (e -> m b) -> Either e a -> m b
- fromEitherOrM_ :: (Applicative m, Monoid b) => Either e a -> (e -> m b) -> m b
- fromMaybeM :: Applicative m => m a -> Maybe a -> m a
- fromMaybeOrM :: Applicative m => Maybe a -> m a -> m a
- fromMaybeM_ :: (Applicative m, Monoid b) => m b -> Maybe a -> m b
- fromMaybeOrM_ :: (Applicative m, Monoid b) => Maybe a -> m b -> m b
- fromEitherMM :: Monad m => (e -> m a) -> m (Either e a) -> m a
- fromEitherOrMM :: Monad m => m (Either e a) -> (e -> m a) -> m a
- fromMaybeMM :: Monad m => m a -> m (Maybe a) -> m a
- fromMaybeOrMM :: Monad m => m (Maybe a) -> m a -> m a
- fromEither :: (e -> a) -> Either e a -> a
- fromEitherOr :: Either e a -> (e -> a) -> a
- fromMaybe :: a -> Maybe a -> a
- fromMaybeOr :: Maybe a -> a -> a
- maybeToEither :: e -> Maybe a -> Either e a
- maybeToEitherOr :: Maybe a -> e -> Either e a
- eitherToMaybe :: Either e a -> Maybe a
- collapseEither :: Either a a -> a
- collapseExceptT :: Monad m => ExceptT a m a -> m a
- collapseErrExceptT :: Monad m => ExceptT (m a) m a -> m a
- liftEitherExceptT :: Applicative m => Either e a -> ExceptT e m a
- fromEitherExceptT :: Monad m => (e -> x) -> Either e a -> ExceptT x m a
- fromEitherOrExceptT :: Monad m => Either e a -> (e -> x) -> ExceptT x m a
- fromEitherMExceptT :: Monad m => (e -> x) -> m (Either e a) -> ExceptT x m a
- fromEitherOrMExceptT :: Monad m => m (Either e a) -> (e -> x) -> ExceptT x m a
- fromMaybeExceptT :: Monad m => x -> Maybe a -> ExceptT x m a
- fromMaybeOrExceptT :: Monad m => Maybe a -> x -> ExceptT x m a
- fromMaybeMExceptT :: Monad m => x -> m (Maybe a) -> ExceptT x m a
- fromMaybeOrMExceptT :: Monad m => m (Maybe a) -> x -> ExceptT x m a
- guardExceptT :: Monad m => Bool -> x -> ExceptT x m ()
- guardMExceptT :: Monad m => m Bool -> x -> ExceptT x m ()

# Monadic in return value

fromEitherM :: Applicative m => (e -> m a) -> Either e a -> m a Source #

A monadic version of `fromEither`

.

`fromEitherM`

leftAction ===`either`

leftAction`pure`

`>>>`

[5]`fromEitherM (\s -> [length s]) $ Right 5`

`>>>`

[3]`fromEitherM (\s -> [length s]) $ Left ("foo" :: String)`

fromEitherOrM :: Applicative m => Either e a -> (e -> m a) -> m a Source #

A `flip`

ed version of `fromEitherM`

.

`>>>`

[5]`fromEitherOrM (Right 5) $ \s -> [length s]`

This can be nice to use as an error handler.

`>>>`

5`fromEitherOrM (Right 5) $ \s -> putStrLn ("error: " ++ s) >> undefined`

`>>>`

error: foo ...`fromEitherOrM (Left "foo") $ \s -> putStrLn ("error: " ++ s) >> undefined`

fromEitherM_ :: (Applicative m, Monoid b) => (e -> m b) -> Either e a -> m b Source #

Similar to `fromEitherM`

, but only run the monadic `leftAction`

if the
`Either`

argument is `Left`

. Otherwise, return `pure`

`mempty`

.

`fromEitherM_`

leftAction ===`either`

leftAction (`const`

`$`

`pure`

`mempty`

)

`>>>`

""`fromEitherM_ (\err -> putStrLn err >> pure "bye") $ Right 5`

`>>>`

there was an error "bye"`fromEitherM_ (\err -> putStrLn err >> pure "bye") $ Left "there was an error"`

This can be convenient when you want to run some sort of logging function
whenever an `Either`

is `Left`

. If you imagine the logging function is
`b -> `

, then the effective type of `IO`

'()'`fromEitherM_`

becomes

, because
'()' has a `fromEitherM_`

:: (e -> `IO`

'()') -> `Either`

e a -> `IO`

'()'`Monoid`

instance, and `IO`

, has an `Applicative`

instance.

`>>>`

there was an error`fromEitherM_ putStrLn $ Left "there was an error"`

fromEitherOrM_ :: (Applicative m, Monoid b) => Either e a -> (e -> m b) -> m b Source #

A `flip`

ed version of `fromEitherM_`

.

fromMaybeM :: Applicative m => m a -> Maybe a -> m a Source #

A monadic version of `fromMaybe`

.

`fromMaybeM`

nothingAction ===`maybe`

nothingAction`pure`

`>>>`

[5]`fromMaybeM [] $ Just 5`

`>>>`

[]`fromMaybeM [] Nothing`

fromMaybeOrM :: Applicative m => Maybe a -> m a -> m a Source #

A `flip`

ed version of `fromMaybeM`

.

`>>>`

[5]`fromMaybeOrM (Just 5) []`

This can be nice to use as an error handler.

`>>>`

5`fromMaybeOrM (Just 5) $ putStrLn "some error occurred" >> undefined`

`>>>`

some error occurred ...`fromMaybeOrM (Nothing) $ putStrLn "some error occurred" >> undefined`

fromMaybeM_ :: (Applicative m, Monoid b) => m b -> Maybe a -> m b Source #

Similar to `fromMaybeM`

, but only run the monadic `nothingAction`

if the
`Maybe`

argument is `Nothing`

. Otherwise, return `pure`

`mempty`

.

`fromMaybeM_`

nothingAction ===`maybe`

nothingAction (`const`

`$`

`pure`

`mempty`

)

`>>>`

""`fromMaybeM_ (putStrLn "hello" >> pure "bye") $ Just 5`

`>>>`

hello "bye"`fromMaybeM_ (putStrLn "hello" >> pure "bye") Nothing`

This can be convenient when you want to run some sort of logging function
whenever a `Maybe`

is `Nothing`

. If you imagine the logging function is

, then the effective type of `IO`

'()'`fromMaybeM_`

becomes

, because '()' has a
`fromMaybeM_`

:: `IO`

'()' -> `Maybe`

a -> `IO`

'()'`Monoid`

instance, and `IO`

, has an `Applicative`

instance.

`>>>`

hello`fromMaybeM_ (putStrLn "hello") Nothing`

fromMaybeOrM_ :: (Applicative m, Monoid b) => Maybe a -> m b -> m b Source #

A `flip`

ed version of `fromMaybeM`

.

# Monadic in both return and sum-type value

fromEitherMM :: Monad m => (e -> m a) -> m (Either e a) -> m a Source #

Similar to `fromEitherM`

but the `Either`

argument is also a monadic value.

`>>>`

[5,10]`fromEitherMM (\s -> [length s]) [Right 5, Right 10]`

`>>>`

[3,100]`fromEitherMM (\s -> [length s]) [Left ("foo" :: String), Right 100]`

**NOTE**: I don't particularly like the name of this function. If you have a
suggestion for a better name, please submit a PR or issue.

fromEitherOrMM :: Monad m => m (Either e a) -> (e -> m a) -> m a Source #

A `flip`

ed version of `fromEitherMM`

.

fromMaybeMM :: Monad m => m a -> m (Maybe a) -> m a Source #

Similar to `fromMaybeM`

but the `Maybe`

argument is also a monadic value.

`>>>`

[6,5]`fromMaybeMM [] [Just 6, Just 5]`

`>>>`

[6,7]`fromMaybeMM [] [Just 6, Nothing, Just 7]`

**NOTE**: I don't particularly like the name of this function. If you have a
suggestion for a better name, please submit a PR or issue.

fromMaybeOrMM :: Monad m => m (Maybe a) -> m a -> m a Source #

A `flip`

ed version of `fromMaybeMM`

.

# Completely non-monadic functions

fromEither :: (e -> a) -> Either e a -> a Source #

Similar to `fromMaybe`

.

`>>>`

"5"`fromEither show $ Left 5`

`>>>`

"hello"`fromEither show $ Right "hello"`

fromEitherOr :: Either e a -> (e -> a) -> a Source #

A `flip`

ed version of `fromEither`

.

fromMaybe :: a -> Maybe a -> a #

The `fromMaybe`

function takes a default value and and `Maybe`

value. If the `Maybe`

is `Nothing`

, it returns the default values;
otherwise, it returns the value contained in the `Maybe`

.

#### Examples

Basic usage:

`>>>`

"Hello, World!"`fromMaybe "" (Just "Hello, World!")`

`>>>`

""`fromMaybe "" Nothing`

Read an integer from a string using `readMaybe`

. If we fail to
parse an integer, we want to return `0`

by default:

`>>>`

`import Text.Read ( readMaybe )`

`>>>`

5`fromMaybe 0 (readMaybe "5")`

`>>>`

0`fromMaybe 0 (readMaybe "")`

# Converting from

`Maybe`

to `Either`

maybeToEither :: e -> Maybe a -> Either e a Source #

maybeToEitherOr :: Maybe a -> e -> Either e a Source #

A `flip`

ed version of `maybeToEither`

.

`>>>`

Right "hello"`maybeToEitherOr (Just "hello") 3`

`>>>`

Left 3`maybeToEitherOr Nothing 3`

eitherToMaybe :: Either e a -> Maybe a Source #

# Collapsing funtions

collapseEither :: Either a a -> a Source #

Collapse an

to an `Either`

a a`a`

. Defined as

.`fromEither`

`id`

Note: Other libraries export this function as `fromEither`

, but our
`fromEither`

function is slightly more general.

`>>>`

3`collapseEither (Right 3)`

`>>>`

"hello"`collapseEither (Left "hello")`

collapseExceptT :: Monad m => ExceptT a m a -> m a Source #

Similar to `collapseEither`

, but for `ExceptT`

.

`>>>`

3`collapseExceptT (ExceptT $ pure (Right 3))`

`>>>`

"hello"`collapseExceptT (ExceptT $ pure (Left "hello"))`

collapseErrExceptT :: Monad m => ExceptT (m a) m a -> m a Source #

Collapse an `ExceptT`

where the error returns the same type as the whole
computation.

`>>>`

`let exceptTOne = pure 3 :: ExceptT (IO Int) IO Int`

`>>>`

3`collapseErrExceptT exceptTOne :: IO Int`

This is helpful when writing short-circuiting computations where you throw errors that match the type of the underlying computation.

`>>>`

let go :: Int -> ExceptT (IO ()) IO () go x = do bar <- if x < 10 then pure "hello" else throwE (putStrLn "Error occurred, x too big!") lift $ putStrLn $ bar ++ " world" :}`:{`

`>>>`

Error occurred, x too big!`collapseErrExceptT (go 100) :: IO ()`

`>>>`

hello world`collapseErrExceptT (go 3) :: IO ()`

In this example, the error type in the `ExceptT`

is

.
This allows us to easily short-circuit the remaining computations.
In this example, the remaining computation is just printing
`IO`

()`bar `

.`++`

" world"

# Converting to

`ExceptT`

liftEitherExceptT :: Applicative m => Either e a -> ExceptT e m a Source #

Lift an `Either`

into an `ExceptT`

.

This is the same as `liftEither`

, but the return type
is specialized for `ExceptT`

.

`>>>`

ExceptT (Identity (Right 3))`liftEitherExceptT (Right 3) :: ExceptT String Identity Int`

Note that if you want to lift `m (`

to `Either`

e a)

,
just use `ExceptT`

e m a`ExceptT`

:

`>>>`

`action = Identity (Left "error") :: Identity (Either String Int)`

`>>>`

ExceptT (Identity (Left "error"))`ExceptT action :: ExceptT String Identity Int`

fromEitherExceptT :: Monad m => (e -> x) -> Either e a -> ExceptT x m a Source #

Lift an `Either`

to an `ExceptT`

with a handler for transforming the error
value.

If the input `Either`

is `Right`

, then just return it like normal:

`>>>`

`let rightEither = Right () :: Either String ()`

`>>>`

ExceptT (Identity (Right ()))`fromEitherExceptT (\str -> length str) rightEither :: ExceptT Int Identity ()`

If the input `Either`

is `Left`

, then pass the value to the handler:

`>>>`

`let leftEither = Left "hello" :: Either String ()`

`>>>`

ExceptT (Identity (Left 5))`fromEitherExceptT (\str -> length str) leftEither :: ExceptT Int Identity ()`

fromEitherOrExceptT :: Monad m => Either e a -> (e -> x) -> ExceptT x m a Source #

Just like `fromEitherExceptT`

, but the arguments are flipped.

fromEitherMExceptT :: Monad m => (e -> x) -> m (Either e a) -> ExceptT x m a Source #

Similar to `fromEitherExceptT`

but the `Either`

value is lifted in a
`Monad`

.

`>>>`

`let identityLeft = Identity (Left "hello") :: Identity (Either String ())`

`>>>`

ExceptT (Identity (Left 5))`fromEitherMExceptT (\str -> length str) identityLeft :: ExceptT Int Identity ()`

This is similar to `withExceptT`

, but the second
argument is the unwrapped `ExceptT`

computation.

fromEitherOrMExceptT :: Monad m => m (Either e a) -> (e -> x) -> ExceptT x m a Source #

Just like `fromEitherOrMExceptT`

, but the arguments are flipped.

fromMaybeExceptT :: Monad m => x -> Maybe a -> ExceptT x m a Source #

Lift a `Maybe`

to an `ExceptT`

with a default value for the case when
the `Maybe`

is `Nothing`

.

If the `Maybe`

is `Just`

, then just return the value like normal:

`>>>`

`let justVal = Just True :: Maybe Bool`

`>>>`

ExceptT (Identity (Right True))`fromMaybeExceptT 5 justVal :: ExceptT Int Identity Bool`

If the `Maybe`

is `Nothing`

, then use the default value as the error value:

`>>>`

`let nothingVal = Nothing :: Maybe Bool`

`>>>`

ExceptT (Identity (Left 5))`fromMaybeExceptT 5 nothingVal :: ExceptT Int Identity Bool`

fromMaybeOrExceptT :: Monad m => Maybe a -> x -> ExceptT x m a Source #

Just like `fromMaybeExceptT`

but with the arguments flipped.

fromMaybeMExceptT :: Monad m => x -> m (Maybe a) -> ExceptT x m a Source #

Similar to `fromMaybeExceptT`

except the `Maybe`

value is lifted in a
`Monad`

.

`>>>`

`let identityNothing = Identity Nothing :: Identity (Maybe Bool)`

`>>>`

ExceptT (Identity (Left 5))`fromMaybeMExceptT 5 identityNothing :: ExceptT Int Identity Bool`

fromMaybeOrMExceptT :: Monad m => m (Maybe a) -> x -> ExceptT x m a Source #

Just like `fromMaybeMExceptT`

but with the arguments flipped.

guardExceptT :: Monad m => Bool -> x -> ExceptT x m () Source #

Similar to `guard`

, but for `ExceptT`

.

If the `Bool`

is `True`

, then do nothing.

`>>>`

ExceptT (Identity (Right ()))`guardExceptT True "error occurred" :: ExceptT String Identity ()`

If the `Bool`

is `False`

, then return the error case:

`>>>`

ExceptT (Identity (Left "error occurred"))`guardExceptT False "error occurred" :: ExceptT String Identity ()`

guardMExceptT :: Monad m => m Bool -> x -> ExceptT x m () Source #

Just like `guardExceptT`

(and similar to `guardM`

), except the boolean is
lifted in a `Monad`

.

`>>>`

ExceptT (Identity (Left "error occurred"))`guardMExceptT (Identity False) "error occurred" :: ExceptT String Identity ()`

# Example converting to

`ExceptT`

Functions like `fromMaybeExceptT`

and `fromEitherExceptT`

are convenient
when paired with `collapseErrExceptT`

. This section explains how
you can use these functions together.

Imagine you're writing a function that pulls user names from a database, reads the first character of the name, and prints it to the console. The functions for reading names from a database, and for parsing the first character of the name could fail, so we will handle these errors by logging to the console.

Here's the function we will be using for pulling user names from
the database. If we pass `0`

, it returns `"SPJ"`

. If we pass `1`

,
it returns an empty string. Otherwise it returns `Nothing`

:

`>>>`

let getUserNameFromDb :: Int -> Maybe String getUserNameFromDb 0 = Just "SPJ" getUserNameFromDb 1 = Just "" getUserNameFromDb _ = Nothing :}`:{`

Here's the function we will be using for parsing the first character
of a user name. If the user name is an empty string, we return
`Left`

with an error message. Otherwise we return the first
character of the user name:

`>>>`

let parseFirstCharFromName :: String -> Either String Char parseFirstCharFromName [] = Left "user name is empty" parseFirstCharFromName (h:_) = Right h :}`:{`

Now let's write our function. If you didn't have the combinators from above
like `fromEitherExceptT`

and `collapseErrExceptT`

, you might be tempted to
write nested `case`

patterns:

`>>>`

let nestedPrintFirstCharOfUserName :: Int -> IO () nestedPrintFirstCharOfUserName i = -- Try to get the username for id i. case getUserNameFromDb i of -- If we couldn't get the user name from the database -- print an error to the console. Nothing -> putStrLn $ "ERROR: couldn't get user name for user " ++ show i Just name -> -- Try to parse the first character of the user name. case parseFirstCharFromName name of -- If we couldn't parse the first character of the user name, -- print an error to the console. Left err -> putStrLn $ "ERROR: " ++ err Right firstChar -> -- Print the first character of the user name to the console. putStrLn $ "Got first character of name for id " ++ show i ++ ": " ++ [firstChar] :}`:{`

Here's an example of using this function, including the error cases:

`>>>`

ERROR: couldn't get user name for user 100`nestedPrintFirstCharOfUserName 100`

`>>>`

ERROR: user name is empty`nestedPrintFirstCharOfUserName 1`

`>>>`

Got first character of name for id 0: S`nestedPrintFirstCharOfUserName 0`

This works, and is understandable, but it gets unwieldy when there are even more parsing steps. You can get very deeply nested cases.

In order to write this without deeply nested error handling, you need a
short-circuiting `Monad`

. Two popular examples are `MaybeT`

and `ExceptT`

.

Using `collapseErrExceptT`

(and `ExcepT`

), it is possible to write this
function by short-circuiting on errors:

`>>>`

let printFirstCharOfUserName :: Int -> IO () printFirstCharOfUserName i = -- The argument to collapseErrExceptT is @ExceptT (IO ()) IO ()@. -- This can be thought of as an action that can short-circuit -- with @IO ()@ error-handling actions. -- -- The error-handling actions below just log to the console. collapseErrExceptT $ do -- Get the user name from the db. -- If getUserNameFromDb returns Nothing, then this whole -- block will short circuit and collapseErrExceptT will -- run our error handler. -- -- Note that for the type of the error handler to work -- correctly with @collapseErrExceptT@, the error -- handler has to return @IO ()@. name <- fromMaybeOrExceptT (getUserNameFromDb i) $ putStrLn $ "ERROR: couldn't get user name for user " ++ show i -- Parse out the first character from the user name. -- If parseFirstCharFromName returns Left, then this whole -- block will short circuit and collapseErrExceptT will -- run our error handler. firstChar <- fromEitherOrExceptT (parseFirstCharFromName name) $ \err -> putStrLn $ "ERROR: " ++ err -- Print the first character of the name. -- This needs to be 'lift'ed because this whole block is -- actually @ExceptT (IO ()) IO ()@. lift $ putStrLn $ "Got first character of name for id " ++ show i ++ ": " ++ [firstChar] :}`:{`

The main good point here is that using the short-circuiting functionality of
`ExceptT`

, we can write everything without nesting.

Here's a few examples of calling `printFirstCharOfUserName`

.

Here we pass a user id that doesn't exist, so `getUserNameFromDb`

will
return `Nothing`

. This causes the function to short-circuit and the
first error handler to be called.

`>>>`

ERROR: couldn't get user name for user 100`printFirstCharOfUserName 100`

Here we pass a user id that does exist, but the user name for this user id is empty. This causes the function to short-circuit and the second error handler to be called.

`>>>`

ERROR: user name is empty`printFirstCharOfUserName 1`

This time the function succeeds:

`>>>`

Got first character of name for id 0: S`printFirstCharOfUserName 0`

In real code, the functions `getUserNameFromDb`

and `parseFirstCharFromName`

will have monadic return values. In that case, you can use
`fromMaybeOrMExceptT`

and `fromEitherOrMExceptT`

.

The following is setup code for doctests in this module.

`>>>`

`import Data.Functor.Identity (Identity(Identity))`