Does MonadTransControl support STM?



我正在寻找一种在STM中原子化地使用monad转换器的标准方法。我觉得这听起来很奇怪,因为到目前为止我发现的所有用例都只是liftIO。原子和传递裸露的"STM a",而不将其包装到任何monad转换器中。我想,因为原子作用通常不是很复杂——只是一个线性和通过局部变量传递自变量更容易且更有效,但在我的情况下,交易量很大,我希望顺利通过主堆栈。

在熟悉了monad控制库之后,我发表了自己的看法如果是源和结果库,则runInBase不能取消调用monad堆栈单子叶是不同的,但我不确定。

inNestedState :: MyData -> StateT MyState STM ()
loadCounterA :: MyData -> StateT MyState IO ()
loadCounterA md = do
control $ runInBase -> atomically (runInBase (inNestedState md))

首次错误

monad-control-demo.hs:29:4: error:
• Couldn't match type ‘STM’ with ‘IO’
Expected type: StateT MyState IO ()
Actual type: StateT MyState STM ()
• In a stmt of a 'do' block:
control $  runInBase -> atomically (runInBase (inNestedState md))
In the expression:
do control
$  runInBase -> atomically (runInBase (inNestedState md))
In an equation for ‘loadCounterA’:
loadCounterA md
= do control
$  runInBase -> atomically (runInBase (inNestedState md))
|
29 |    control $ runInBase -> atomically (runInBase (inNestedState md))

与此同时,我最终得到了有限但方便的自制解决方案:

class MonadRebase m n where
rebase :: (m a) -> (n a)
instance (MonadRebase m n) => MonadRebase (ReaderT r m) (ReaderT r n) where
rebase t = ReaderT $ r -> rebase (runReaderT t r)
instance (MonadRebase m n) => MonadRebase (StateT s m) (StateT s n) where
rebase t = StateT $ s -> rebase (runStateT t s)
instance MonadRebase STM IO where
rebase = atomically
data MyState = MyState {
msCounter1 :: TVar Int,
msCounter2 :: TVar Int,
ops :: Int
}
inStm :: ReaderT Int (StateT MyState STM) ()
inStm = do
rInt <- ask
lift $ do
mySt <- get
modify (st -> st {ops = rInt + ops st })
lift $ do
c1Val <- (readTVar (msCounter1 mySt))
c2Val <- (readTVar (msCounter2 mySt))
writeTVar (msCounter1 mySt) 0
writeTVar (msCounter2 mySt) (c1Val + c2Val)
foo :: ReaderT Int (StateT MyState IO) ()
foo = do
rebase inStm

任何关于如何对现有图书馆进行同样处理的想法都将受到赞赏。

我将您的问题解释为"如何将StateT MyState STM ()转换为StateT MyState IO ()?"。答案是mapStateT:

loadCounterA = mapStateT atomically . inNestedState

如第二个示例所示,要深入到变压器堆栈的多个层,只需嵌套变压器各自的map函数的应用程序:

foo = mapReaderT (mapStateT atomically) inStm

当你有一个大的转换器堆栈时,这可能有点麻烦,但由于类型检查器,这类代码不会出错。

相关内容

最新更新