A continuation of a previous page on extensible-effects.

Oleg suggested to me the following example which shows how easily one can abstract the client in the Extensible Effects framework:

```
c5 = runTrace $ runReader (loop =<< runC (th client)) (10::Int)
where loop (Y x k) = trace (show (x::Int)) >> local (+(1::Int)) (k ()) >>= loop
loop Done = trace "Done"
-- cl, client, ay are monomorphic bindings
client = ay >> ay
ay = ask >>= \x -> yield (x::Int)
-- There is no polymorphic recursion here
th cl = do
cl
v <- ask
(if v > (20::Int) then id else local (+(5::Int))) cl
if v > (20::Int) then return () else local (+(10::Int)) (th cl)
{-
The expected result is:
10
11
16
16
21
21
21
21
Done
-}
```

The same result can be achieved with the MTL, but the `CoT`

type needs
a `MonadFunctor`

instance so that we can use `hoist`

. I don’t know if
`CoT`

as implemented via `ContT`

can be given such an instance. As
such I implemened my own version like this

```
data Step y m a = Done a | Yield y (CoT y m a)
data CoT y m a = CoT (m (Step y m a))
```

and then we can reimplement `c5`

straightforwardly

```
c5 :: IO ()
c5 = runReaderT (loop =<< runC (th client)) (10::Int)
where loop (Yield x k) = (liftIO . print) (show (x::Int)) >> local (+(1::Int)) (runC k) >>= loop
loop (Done _) = (liftIO . print) "Done"
-- Type signatures are not required, but I will
-- say what they are anyway.
-- client :: (MonadCo r m, MonadReader r m) => m ()
client = ay >> ay
-- ay :: (MonadCo r m, MonadReader r m) => m ()
ay = ask >>= yieldG
-- th :: (Monad m, MFunctor t, Monad (t (ReaderT Int m)),
-- MonadReader Int (t (ReaderT Int m)))
-- => t (ReaderT Int m) () -> t (ReaderT Int m) ()
th cl = do
cl
v <- ask
(if v > (20::Int) then id else hoist (localLocal' (+(5::Int)))) cl
if v > (20::Int) then return () else hoist (localLocal' (+(10::Int))) (th cl)
```

The reimplementation is remarkably similar to the original with just
some `hoist`

s added. Running it gives exactly the result desired

```
GHCi> c5
"10"
"11"
"16"
"16"
"21"
"21"
"21"
"21"
"Done"
```

Note: Later Oleg pointed out to me that the definition of `th`

above
only works on transformer stacks two deep, where the second is
`ReaderT`

. It seems to me that any more deeply nested stack can be
converted to one where the ReaderT occurs at the second layer, using,
for example

`ComposeTrans t1 t2 m = ComposeTrans (t1 (t2 m))`

and if we want the ReaderT to occur at the first layer, we can just wrap it in IdentityT instead.

However, this introduces a lot more awkwardness which Extensible Effects doesn’t have, the latter being designed exactly to avoid this kind of thing. So perhaps this is a good example to demonstrate exactly what problem it is that Extensible Effects solves.

The concept of `MFunctor`

and its method `hoist`

seem to play a
crucial role here. In the case of a free monad I would guess that the
`MFunctor`

instance comes for free, i.e. free monads always support
`hoist`

. This seems to be a crucial missing element from the MTL to
allow effects to work with each other in a generic manner. I need to
think about this more …