Monad transformers are the standard way to extend monads. The transformers package defines monad transformers.

`StateT`

, one of the representative monad transformers, has three parameters:

`newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }`

The second parameter `m`

allows you to add a new type of effect while preserving
the original monad. This is characterised by `MonadTrans`

:

```
class MonadTrans t where
lift :: Monad m => m a -> t m a
instance MonadTrans (StateT s) where
lift m = StateT $ \s -> (\a -> (a, s)) <$> m
```

As a monad transformer stack gets deeper, it gets more inconvenient to apply
`lift`

s. mtl provides type classes
in order to avoid this.

`MonadState s`

is such a class; this is the class of monads which have an access
to a state `s`

.

```
class MonadState s m | m -> s where
get :: m s
put :: s -> m ()
state :: (s -> (a, s)) -> m a
```

`StateT s m`

is an instance of `MonadState s`

.

```
instance Monad m => MonadState s (StateT s m) where
get = StateT $ \s -> return (s, s)
put s = StateT $ const $ return ((), s)
...
```

Also, other monad transformers are also instances, when their inner monads are
`MonadState`

. Their methods are just `lift`

ed.

```
instance MonadState s m => MonadState (ReaderT r m) where
get = lift get
put = lift . put
instance (Monoid w, MonadState s m) => MonadState (WriterT w m) where
get = lift get
put = lift . put
```

This way you don't have to care about the number of `lift`

s, and you can define
polymorphic functions using these classes.

However, for library designers, this is a big pain. Basically this kind of class can be defined for each monad; this means adding a monad transformer has a quadratic development cost. It also makes packaging significantly harder.

## Extensible effects

Extensible effects is a solution to this problem. The extensible effects framework provides a monad parameterised by a type-level list of effects.

One recent implementation is freer-effects.

In this framework, you don't have to deal with other monads in order to define a new type of effect.

`send`

makes a big difference; it can be thought of as universal `lift`

.
As long as `t`

is a member of `r`

, you can embed an action to `Eff`

.

`send :: Member t r => t v -> Eff r v`

A state monad can be defined as follows:

```
data State s v where
Get :: State s s
Put :: !s -> State s ()
get :: Member (State s) r => Eff r s
get = send Get
put :: Member (State s) r => s -> Eff r ()
put = send . Put
```

`handleRelayS`

decomposes `Eff`

in a stateful manner.

```
handleRelayS :: s
-> (s -> a -> Eff r w)
-> (forall v. s -> t v -> (s -> v -> Eff r w) -> Eff r w)
-> Eff (t ': r) a
-> Eff r w
```

The following example interprets the `State`

actions.

```
runState :: Eff (State s ': r) a -> s -> Eff r (a, s)
runState m s0 = handleRelayS s0 (\s a -> return (a, s))
(\s t k -> case t of
Get -> k s s
Put s' -> k s' ()) m
```

While this seems very good, it leaves one issue.

Unlike `MonadState`

, In a constraint `Member (State s) r`

, `r`

doesn't determine
the type of `s`

. This means that you can't use a polymorphic effect without a
type signature:

```
increment :: (Num a, Member (State a) r) => Eff r ()
increment = get >>= put . (+1)
```

This is annoying, and I think this is one reason why extensible effects are not popular.

## Named extensible effects

My extensible library solves this problem by giving names to effects.

```
liftEff :: forall s t xs a. Associate s t xs
=> Proxy s
-> t a
-> Eff xs a
```

`liftEff`

is like `send`

, but `Proxy s`

specifies the name. `Associate s t xs`

requires that the effect corresponding to name `s`

is `t`

in `xs`

. This version
doesn't suffer from the ambiguity problem because `s`

and `xs`

determines `t`

.

Various operations take names:

```
getEff :: forall k s xs. Associate k (State s) xs => Proxy k -> Eff xs s
putEff :: forall k s xs. Associate k (State s) xs => Proxy k -> s -> Eff xs ()
```

`Eff`

in `extensible`

is also an instance of `MonadState`

so you can simply write

```
increment :: (Num a, MonadState a m) => m ()
increment = get >>= put . (+1)
```

The equivalent of
`handleRelayS`

is `peelEff`

. Note that the order of arguments is different.

```
peelEff1 :: (a -> b -> Eff xs r) -- ^ return the result
-> (forall x. t x -> (x -> b -> Eff xs r) -> b -> Eff xs r) -- ^ Handle the foremost type of an action
-> Eff (k >: t ': xs) a -> b -> Eff xs r
peelEff1 = peelEff rebindEff1
```

Here's an example. You can use `TypeApplications`

extension to specify a name.

```
runStateEff :: forall k s xs a. Eff (k >: State s ': xs) a -> s -> Eff xs (a, s)
runStateEff = peelEff1 (\a s -> return (a, s))
(\m k s -> let (a, s') = runState m s in k a $! s')
```

It's also possible to handle multiple effects which have the same type.

```
{-# LANGUAGE DataKinds, FlexibleContexts, OverloadedLabels #-}
import Data.Extensible
test :: (Associate "foo" ((,) String) xs
, Associate "bar" ((,) String) xs) => Eff xs ()
test = do
tellEff #foo "Hello "
tellEff #bar "foo"
tellEff #foo "world"
tellEff #bar "bar"
```

```
> leaveEff $ runWriterEff @ "foo" $ runWriterEff @ "bar" test
(((),"foobar"),"Hello world")
```

## Performance

I did some benchmarks on RWS equivalents. Unfortunately, it's much slower than monad transformers.

## Conclusion

The idea of extensible effects is promising to avoid the issue of quadratic monad class instances. However, the performance is sluggish. For time being, there is a trade-off between convenience and performance.