MonadTransControl instance for a custom monad

haskell, monad-transformers, monads

Solution

I haven't been able to reuse `defaultLiftWith` and `defaultRestoreT`, but looking at their source code and tweaking it slightly, I arrived at the following:

newtype CounterT m a = CounterT {unCounterT :: MaybeT (StateT Int m) a} deriving (Monad)

instance MonadTrans CounterT where
    lift = CounterT .  lift . lift

instance MonadTransControl CounterT where
     newtype StT CounterT a = StCounter {unStCounter :: StT (StateT Int) (StT MaybeT a)}
     liftWith = \f -> 
        CounterT $ liftWith $ \run -> 
                   liftWith $ \run' -> 
                   f $ liftM StCounter . run' . run . unCounterT            
     restoreT = CounterT . restoreT . restoreT . liftM unStCounter

Problem

The docs for `monad-control` provide an example on how to create an instance of `MonadTransControl` using `defaultLiftWith` and `defaultRestoreT`. The example is for the following `newtype`: ``` newtype CounterT m a = CounterT {unCounterT :: StateT Int m a} ``` This example can be adjusted to work for any `newtype` that is defined using only one "elementary" monad transformer (such as the ones from `transformers` or `mtl`). But what about the case where the stack contains two "elementary" transformers? For example, how can we define a `MonadTransControl` instance for something like this: ``` newtype T m a = T {unT :: MaybeT (StateT Int m) a} ``` My problem is that I don't know how to adjust the following line ``` newtype StT CounterT a = StCounter {unStCounter :: StT (StateT Int) a} ``` from the `CounterT` to make it work for my `T` transformer. In particular, I don't know what to put in last parenthesis. It expects something that has kind `(* -> *) -> * -> *`, but I cannot form anything like that. Any ideas?

Original source