Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MonadTransControl instance for a custom monad

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?

like image 569
safsaf32 Avatar asked Oct 22 '22 05:10

safsaf32


1 Answers

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
like image 180
danidiaz Avatar answered Oct 24 '22 12:10

danidiaz