2

请看下面liftIO函数中的使用increment。我有一种预感,使用镜头可以更好地处理它。有什么建议么?

{-# 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 ()
4

1 回答 1

2

我之前(几乎)写过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 
于 2013-11-25T14:41:34.167 回答