monad-control
的文档提供了有关如何使用MonadTransControl
创建实例的示例
defaultLiftWith
和defaultRestoreT
。该示例适用于以下newtype
:
newtype CounterT m a = CounterT {unCounterT :: StateT Int m a}
此示例可以调整为适用于仅使用一个“基本”monad变换器(例如来自newtype
或transformers
的变换器)定义的任何mtl
。但是堆栈包含两个“基本”变换器的情况又如何呢?例如,我们如何为这样的事物定义MonadTransControl
实例:
newtype T m a = T {unT :: MaybeT (StateT Int m) a}
我的问题是我不知道如何调整以下行
newtype StT CounterT a = StCounter {unStCounter :: StT (StateT Int) a}
来自CounterT
的使其适用于我的T
转换器。特别是,我不知道在最后一个括号中放什么。它期望有类似(* -> *) -> * -> *
的东西,但我不能形成类似的东西。
有什么想法吗?
答案 0 :(得分:3)
我无法重复使用defaultLiftWith
和defaultRestoreT
,但查看其源代码并稍微调整一下,我得出以下结论:
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