haskell - 使用透镜对 StateT 中的内部单子(monad)进行操作

标签 haskell haskell-lens

请参阅下面的increment函数中liftIO的使用。我有预感,有更好的方法可以使用镜头来处理它。有什么建议吗?

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens
import Control.Monad.IO.Class
import Control.Monad.State

data PersistentCounter = PersistentCounter {
    _cValue :: Int,
    _cFilename :: FilePath
  } deriving Show
makeLenses ''PersistentCounter

increment :: StateT PersistentCounter IO ()
increment = do
  t <- cValue <+= 1
  f <- use cFilename
  liftIO $ writeFile f $ show t

编辑:我认为可能有一种类似于下面的“zoom2”的机制。

increment :: StateT PersistentCounter IO ()
increment = do
  t <- cValue <+= 1
  zoom2 store 

store :: PersistentCounter -> IO ()
store counter =
  writeFile (counter^.cFilename) $ show (counter^.cValue)

-- | Invoke a function in the inner monad, and pass the state as
--   a parameter.
zoom2 :: Monad m => (s -> m ()) -> StateT s m ()
zoom2 f = get >>= (\s -> lift (f s)) >> return ()

最佳答案

我之前(几乎)写过很多次zoom2——我通常称之为getsM。通用版本看起来像

-- from Control.Monad.State
gets  :: MonadState s m => (s ->   a) -> m a
getsM :: MonadState s m => (s -> m a) -> m a
getsM f = state  $ \s -> (,s) <$> f s

或者,如果您不介意修复特定堆栈

-- from Control.Monad.Trans.State
gets  :: Monad m => (s ->   a) -> StateT s m a
getsM :: Monad m => (s -> m a) -> StateT s m a 
getsM f = StateT $ \s -> (,s) <$> f s 

关于haskell - 使用透镜对 StateT 中的内部单子(monad)进行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20190722/

相关文章:

haskell - 在 Haskell 中,我们什么时候使用 in 和 let ?

haskell - Conduit - 将 ByteString 源拆分为字节 block

haskell - 使用通用量化约束重写规则/特化类型错误

haskell - 当我的 getter 和 setter 返回 `Either` 时,我可以构建类似镜头的东西吗?

haskell - 如何使用镜头在嵌套 map 中设置值

haskell - 如何在 "parallel"中组合镜头

haskell 错误: "First argument in (n+k) pattern must be a variable" - but how?

haskell - 加速 runhaskell

haskell - 在 Haskell 中将整数输出到标准输出

haskell - Setter 保留索引是什么意思?