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?