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?

Original source