Dan Doel dan.doel at gmail.com
Sat Aug 12 04:05:56 EDT 2006

```On 8/11/06, Dan Doel <dan.doel at gmail.com> wrote:
> The difference is in what the parameters to the classes MonadTrans and
> IO-actions can be lifted. MonadTrans t means that (t m) is a monad
> into which m-actions can be lifted. However, since the type class
> doesn't know about m, it's impossible to exprss that composition of
> two transformers is itself a transformer, whereas you can easily
> declare that the result of transforming a MonadIO with a certain
> transformer results in a MonadIO.

I played around a bit, and I was essentially able to express
composition of transformers without extra class parameters. Ideally,
it'd go something like this:

type CombinatorT (t :: (* -> *) -> * -> *)
(u :: (* -> *) -> * -> *)
(m :: * -> *)
(a :: *) = t (u m) a

lift = lift . lift

This says that the combinator transformer is a monad transformer if t
and u are. However, since the combinator transformer is just a type
synonym, it would (I think) end up reducing to all combinations of
transformers being transformers.

However, partially applied type synonyms aren't allowed (for good
reasons, I hear; this example is particularly weird; is it possible to
write without using type synonym syntax? MonadTrans (forall m. t (u
m)) ?), so instead, you have to use a data declaration (maybe a
newtype? I don't know):

CombinatorT t u m a = CombinatorT (m a)

lift = CombinatorT

However, that doesn't really give the types we want, and obviously
doesn't do the lift composition, so we need a way to get it out of the
container:

CombinatorT t u m a -> t (u m) a
unC (CombinatorT m)= lift (lift m)

And for less typing:

liftC = unC . lift

And now an example, shamefully stolen from Mr. Kuklewicz

type Foo a = (WriterT [Int] (ReaderT String [])) a

foo :: Foo String
foo = do
x <- liftC [1, 2, 3]
tell [succ x]
return (s ++ show x)

test = runReaderT (runWriterT foo) "hello"

*Transform> test
[("hello1",[2]),("hello2",[3]),("hello3",[4])]

Viola.
-- Dan
```