How to nest monads
haskell, monads
Solution
Welcome to the wonderful world of Monad Transformers. There's a nice library called the MTL that provides the "monad transformer" equivalents of most monads. By convention, these end with a capital T, so `StateT` is what we want. Monad transformers have their usual operations and one more, `lift`, for a `StateT` that looks like this,
lift :: Monad m => m a -> StateT s m a
Now there's a special class for transformers on top of `IO` called `MonadIO`. To use it, we'd do something like. It's similar to just a plain old monad transformer but has the type signature
liftIO :: (MonadIO m, Monad m) => IO a -> m a
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's a handy set of functions that turn `StateT s m a`'s into `s -> (s, a)`.
main :: IO ()
main = do
(x,s) <- runStateT (runUntil (< 10) simpleState) 0
putStrLn $ "State = " ++ (show s) ++ " Result = " ++ (show x)
Notice that now we use bind (the `<-`) because the result is in `IO`, it's no longer pure. Monad transformers can be pretty confusing, luckily Real World Haskell has a chapter on them. If you're confused it's worth looking at.
Problem
I have this code in Haskell: ``` import Control.Monad.Trans.State simpleState = state (\x -> (x, x + 1)) runUntil :: (s -> Bool) -> State s a -> State s a runUntil f s = do s' <- get -- Here I want to print value of s' to console if f s' then s >> runUntil f s else s main :: IO () main = do let (x,s) = runState (runUntil (< 10) simpleState) 0 putStrLn $ "State = " ++ (show s) ++ " Result = " ++ (show x) ``` I want to print the value of the state on each iteration of runUntil. If I can't print it in `runUntil` function where I can do this?