Safe Haskell | Safe |
---|---|

Language | Haskell98 |

- with :: Monad m => Handler e r m a -> (Effect e m -> Layer e m a) -> m r
- run :: Base Pure a -> a
- data Handler e r m a = Handler {}
- operation :: AutoLift e m n => Effect e m -> ((a -> m e) -> m e) -> n a
- runBase :: Base m a -> m a
- base :: AutoLiftBase m n => m a -> n a
- newtype Layer e m a = Layer {
- runLayer :: (a -> m e) -> m e

- newtype Base m a = Base (m a)
- newtype Pure a = Pure a
- data Effect e m
- class (Applicative m, Applicative n, Monad m, Monad n) => AutoLift e m n
- class (Applicative m, Applicative n, Monad m, Monad n) => AutoLiftBase m n

# Running effects

Here's an example how to use the state effect from `State`

:

example :: Int example = run $ do with (ref 10) $ \u -> do val <- get u put u (val + 5) get u

with :: Monad m => Handler e r m a -> (Effect e m -> Layer e m a) -> m r Source #

`with`

takes a handler and creates a new effect instance.
The `Effect`

is passed on to a function which can use it to do operations with it.

# Defining effects

Here's and example how to define the state effect from `Writer`

:

writer :: (Monad m, Monoid w) => Handler (w, a) (w, a) m a writer = Handler { ret = \a -> return (mempty, a) , fin = return } tell :: (AutoLift (w, r) m n, Monoid w) => Effect (w, r) m -> w -> n () tell p v = operation p $ \k -> do (w, r) <- k () return (mappend v w, r)

A `Handler e r m a`

is a handler of effects with type `e`

.
The `ret`

field provides a function to lift pure values into the effect.
The `fin`

field provides a function to extract a final value of type `r`

from the effect.
The parameter `m`

should normally be left polymorphic, it's the monad that handles the other effects.

operation :: AutoLift e m n => Effect e m -> ((a -> m e) -> m e) -> n a Source #

`operation`

takes an effect identifier generated by `with`

and a function which takes a continuation as parameter.
The result is auto-lifted so it can be used inside any other effect.

# Base monad

The effects are layered on top of a base monad. Here's an example how to use `IO`

as a base monad:

exampleIO :: IO () exampleIO = runBase $ do with (ref 5) $ \x -> do val <- get x base $ print val

base :: AutoLiftBase m n => m a -> n a Source #

`base`

takes a computation in the base monad and auto-lifts it so it can be used inside any effect.

# Effects machinery

Effects are layered in a stack on top of a base monad. Just like with monad transformers, operations lower in the stack
need to be lifted to be able to be used together with operations higher in the stack. But as there are only two monads
in play, `Layer`

and `Base`

, and because each operation is identified with exactly one layer using the `Effect`

type,
lifting can be done automatically.

The following types and classes show up in the type signatures. The compiler should be able to infer them for you.

`Layer e m`

is a monad that adds an effect `e`

to the underlying monad `m`

.
(It is the continuation monad transformer with a friendlier name.)

(Applicative m, Monad m, AutoLiftInternal (Layer e m) (Layer d n) (Layer e m) (Layer d n)) => AutoLift e m (Layer d n) Source # | |

(Applicative m, Monad m, AutoLiftInternal (Base m) (Layer e n) (Base m) (Layer e n)) => AutoLiftBase m (Layer e n) Source # | |

Monad (Layer e m) Source # | |

Functor (Layer e m) Source # | |

Applicative (Layer e m) Source # | |

(Monoid e, Applicative m) => Alternative (Layer e m) Source # | |

(Monoid e, Applicative m) => MonadPlus (Layer e m) Source # | |

`Base m`

is a newtype wrapper around a monadic computation.

Base (m a) |

(Applicative m, Applicative n, Monad m, Monad n, AutoLiftInternal (Layer e m) (Base n) (Layer e m) (Base n)) => AutoLift e m (Base n) Source # | |

(Applicative m, Applicative n, Monad m, Monad n, AutoLiftInternal (Base m) (Base n) (Base m) (Base n)) => AutoLiftBase m (Base n) Source # | |

Monad m => Monad (Base m) Source # | |

Functor m => Functor (Base m) Source # | |

Applicative m => Applicative (Base m) Source # | |

`Pure`

is the identity monad and is used when no other base monad is needed.

Pure a |

`Effect e m`

is a proxy for the type checker to be able to work with multiple effects at the same time.

class (Applicative m, Applicative n, Monad m, Monad n) => AutoLift e m n Source #

operation'

class (Applicative m, Applicative n, Monad m, Monad n) => AutoLiftBase m n Source #

base'

(Applicative m, Applicative n, Monad m, Monad n, AutoLiftInternal (Base m) (Base n) (Base m) (Base n)) => AutoLiftBase m (Base n) Source # | |

(Applicative m, Monad m, AutoLiftInternal (Base m) (Layer e n) (Base m) (Layer e n)) => AutoLiftBase m (Layer e n) Source # | |