首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MonadTransControl是否支持STM?

MonadTransControl是否支持STM?
EN

Stack Overflow用户
提问于 2020-05-05 02:34:56
回答 1查看 89关注 0票数 1

我正在寻找一种在STM.atomically中使用monad转换器的标准方法。我认为这听起来很奇怪,因为到目前为止我发现的所有用例都只有liftIO。原子地传递空的"STM a“,而不把它包装到任何monad转换器中。我猜,因为原子操作通常不是很复杂--只需要一个内联程序,而且通过局部变量传递参数更容易、更有效,但在我的例子中,事务很大,我希望顺利地传递主堆栈。

在熟悉了monad控件库之后,我倾向于认为如果源代码和结果库monad不同,runInBase就不能解除monad堆栈,但我不确定。

代码语言:javascript
复制
inNestedState :: MyData -> StateT MyState STM ()

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

第一个错误

代码语言:javascript
复制
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))

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

代码语言:javascript
复制
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

任何关于如何对已有的库做同样的事情的想法都将受到欢迎。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-06 05:11:07

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

代码语言:javascript
复制
loadCounterA = mapStateT atomically . inNestedState

要向下查看转换器堆栈的多个层,如第二个示例所示,只需嵌套转换器各自的map函数的应用程序:

代码语言:javascript
复制
foo = mapReaderT (mapStateT atomically) inStm

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61599227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档