-- | -- general usefull state monad for a local state and IO -- -- This module is used for threading a state and io actions -- through a computation. -- Here the monad is constructed by hand. -- It could easily be refactored with the use of the monad transformer library. module Control.Monad.MonadStateIO ( module Control.Monad.MonadStateIO ) where import System.IO -- ------------------------------------------------------------ newtype StateIO state res = STIO { trans :: state -> IO (res, state) } instance Monad (StateIO state) where return v = STIO ( \s -> return (v, s)) STIO cmd >>= f = STIO ( \s -> cmd s >>= \ (rl, s') -> (trans . f) rl s' ) -- ------------------------------------------------------------ -- | -- lift IO command to 'StateIO' io :: IO a -> StateIO state a io iocmd = STIO ( \s -> do a <- iocmd return (a, s) ) -- ------------------------------------------------------------ -- | -- state inspection command: a \"show\"-like function is applied to the state -- and the result is written to stderr. trcState :: (state -> String) -> StateIO state () trcState fct = STIO ( \s -> do hPutStr stderr $ fct s return ((), s) ) -- ------------------------------------------------------------ -- -- state access commands -- | -- change the state with a given function and return the new state changeState :: (state -> state) -> StateIO state state changeState f = STIO ( \s -> let s' = f s in return (s', s') ) -- | -- set the state setState :: state -> StateIO state state setState s = changeState ( \_ -> s ) -- | -- read the state getState :: StateIO state state getState = changeState id -- ------------------------------------------------------------ -- | -- run a 'StateIO' command with an initial state run :: state -> StateIO state res -> IO res run initialState (STIO cmd) = do (res, _finalState) <- cmd initialState return res -- ------------------------------------------------------------