问题
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