MonadTransControl支持STM吗?

问题描述 投票:1回答:1

我正在寻找一种标准的方法来在STM.原子中使用单体变换器,我认为这听起来很奇怪,因为到目前为止,我发现的所有用例都只是原子地解除IO.并传递裸露的 "STM a",而没有将其包装到任何单体变换器中。我猜测,因为原子操作通常不是很复杂--只是单线,而且通过局部变量传递参数更容易和更有效,但在我的案例中,事务是很大的,我希望顺利地传递主栈。

在熟悉了单体控制库之后,我倾向于认为如果源基和结果基单体不同,runInBase不能解除单体栈,但我不确定。

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

任何关于如何在现有库中做同样的事情的想法都将受到重视。

haskell monads monad-transformers
1个回答
1
投票

我把你的问题理解为 "我怎么能把一个......转换为......"。StateT MyState STM ()StateT MyState IO ()?". 答案是:"? mapStateT:

loadCounterA = mapStateT atomically . inNestedState

要在变压器堆栈的多个层中向下移动,就像您的第二个例子一样,只需将变压器各自的应用嵌套在一起。map 函数。

foo = mapReaderT (mapStateT atomically) inStm

当你有一个大的变压器堆栈时,这可能会有点麻烦, 但由于类型检查器的存在,这种代码是不会错的。

© www.soinside.com 2019 - 2024. All rights reserved.