Welcome to the wonderful world of Monad Transformers. There's a good library called MTL that provides the equivalents of the “monad transformer" of most monads. By convention, they end in capital T, so StateT is what we want. Monad transformers have their usual operations and another, lift , for StateT , which looks like this:
lift :: Monad m => ma -> StateT sma
Now there is a special class for transformers on top of the IO , called MonadIO . To use it, we would do something like this. It looks like a simple old monad transformer, but has a signature like
liftIO :: (MonadIO m, Monad m) => IO a -> ma import Control.Monad.State import Control.Monad.Trans simpleState :: StateT Integer IO () simpleState = modify (+1) runUntil :: Show s => (s -> Bool) -> StateT s IO a -> StateT s IO s runUntil pred newState = do curr <- get if pred curr then liftIO (print curr) >> newState >> runUntil pred newState else return curr
Then, to run it, there is a convenient set of functions that turn StateT sma into s -> (s, a) .
main :: IO () main = do (x,s) <- runStateT (runUntil (< 10) simpleState) 0 putStrLn $ "State = " ++ (show s) ++ " Result = " ++ (show x)
Note that we are now using bind ( <- ), because the result is in IO , it is no longer pure. Monad transformers can be quite confusing, fortunately Real World Haskell has a chapter about them. If you're confused, it's worth a look.
jozefg
source share