Reputation: 8126
Pleease see the use of liftIO
in the function increment
below. I have a hunch that there's a better way to handle it using lenses. Any suggestions?
{-# 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
EDIT: I thought there might be a mechanism something like `zoom2, below.
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 ()
Upvotes: 2
Views: 552
Reputation: 74344
I've written (almost) zoom2
many times before---I usually call it getsM
. A generic version looks like
-- 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
Or if you don't mind fixing a particular stack
-- 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
Upvotes: 2