MonadTransControl instance for a custom monad

最后都变了- 提交于 2019-12-23 10:38:51

问题


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?


回答1:


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


来源:https://stackoverflow.com/questions/17653666/monadtranscontrol-instance-for-a-custom-monad

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!