请注意在下面的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
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 ()
答案 0 :(得分: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