Portability | semi-portable (Rank2Types, MPTCs, FlexibleInstances) |
---|---|

Stability | provisional |

Maintainer | wren@community.haskell.org |

Safe Haskell | Safe-Inferred |

A continuation-passing variant of `Either`

for short-circuiting
at failure. This code is based on Control.Monad.MaybeK.

- data EitherK e a
- runEitherK :: EitherK e a -> Either e a
- toEitherK :: Either e a -> EitherK e a
- eitherK :: (e -> b) -> (a -> b) -> EitherK e a -> b
- throwEitherK :: e -> EitherK e a
- catchEitherK :: EitherK e a -> (e -> EitherK f a) -> EitherK f a
- data EitherKT e m a
- runEitherKT :: Monad m => EitherKT e m a -> m (Either e a)
- toEitherKT :: Monad m => Either e a -> EitherKT e m a
- liftEitherK :: Monad m => EitherK e a -> EitherKT e m a
- lowerEitherK :: Monad m => EitherKT e m a -> m (EitherK e a)
- throwEitherKT :: Monad m => e -> EitherKT e m a
- catchEitherKT :: Monad m => EitherKT e m a -> (e -> EitherKT f m a) -> EitherKT f m a

# The short-circuiting monad

A continuation-passing encoding of `Either`

as an error monad;
also known as `Codensity (Either e)`

, if you're familiar with
that terminology. N.B., this is not the 2-continuation implementation
based on the Church encoding of `Either`

. The latter tends to
have worse performance than non-continuation based implementations.

This is generally more efficient than using `Either`

(or the
MTL's `Error`

) for two reasons. First is that it right associates
all binds, ensuring that bad associativity doesn't artificially
introduce midpoints in short-circuiting to the nearest handler.
Second is that it removes the need for intermediate case
expressions.

Another benefit over MTL's `Error`

is that it doesn't artificially
restrict the error type. In fact, there's no reason why `e`

must
denote "errors" per se. This could also denote computations
which short-circuit with the final answer, or similar methods
of non-local control flow.

N.B., the `Alternative`

and `MonadPlus`

instances are left-biased
in `a`

and monoidal in `e`

. Thus, they are not commutative.

MonadError e (EitherK e) | |

Monad (EitherK e) | |

Functor (EitherK e) | |

Monoid e => MonadPlus (EitherK e) | |

Applicative (EitherK e) | |

Monoid e => Alternative (EitherK e) |

runEitherK :: EitherK e a -> Either e aSource

Execute an `EitherK`

and return the concrete `Either`

encoding.

eitherK :: (e -> b) -> (a -> b) -> EitherK e a -> bSource

A version of `either`

on `EitherK`

, for convenience. N.B.,
using this function inserts a case match, reducing the range of
short-circuiting.

throwEitherK :: e -> EitherK e aSource

Throw an error in the `EitherK`

monad. This is identical to
`throwError`

.

catchEitherK :: EitherK e a -> (e -> EitherK f a) -> EitherK f aSource

Handle errors in the `EitherK`

monad. N.B., this type is more
general than that of `catchError`

, allowing the type of the
errors to change.

# The short-circuiting monad transformer

A monad transformer version of `EitherK`

.

Monad m => MonadError e (EitherKT e m) | |

MonadTrans (EitherKT e) | |

Monad (EitherKT e m) | |

Functor (EitherKT e m) | |

(Monad m, Monoid e) => MonadPlus (EitherKT e m) | |

Applicative (EitherKT e m) | |

(Monad m, Monoid e) => Alternative (EitherKT e m) |

runEitherKT :: Monad m => EitherKT e m a -> m (Either e a)Source

Execute an `EitherKT`

and return the concrete `Either`

encoding.

toEitherKT :: Monad m => Either e a -> EitherKT e m aSource

Lift an `Either`

into an `EitherKT`

.

liftEitherK :: Monad m => EitherK e a -> EitherKT e m aSource

Lift an `EitherK`

into an `EitherKT`

.

lowerEitherK :: Monad m => EitherKT e m a -> m (EitherK e a)Source

Lower an `EitherKT`

into an `EitherK`

.

throwEitherKT :: Monad m => e -> EitherKT e m aSource

Throw an error in the `EitherKT`

monad. This is identical to
`throwError`

.

catchEitherKT :: Monad m => EitherKT e m a -> (e -> EitherKT f m a) -> EitherKT f m aSource

Handle errors in the `EitherKT`

monad. N.B., this type is more
general than that of `catchError`

, allowing the type of the
errors to change.