Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - no output from within StateT monad

Tags:

haskell

Trying to familiarize myself with monad transformers, I wrote the following piece of code:

data GlobalState = GlobalState {
        rng :: StdGen 
}

foo :: IO ()
foo = 
        evalStateT ( StateT $ 
                   \s -> 
                   let (v, newrng) = roll $ rng s in 
                         return (putStrLn $ show v, 
                                 s { rng = newrng })
        ) zeroState >>
        putStrLn "See you soon."

zeroState :: GlobalState
zeroState = GlobalState {
        rng = mkStdGen 0
}

roll :: StdGen -> (Int, StdGen)
roll gen = randomR (1, 6) gen

The idea was to initialize state, use it for an IO action and return back to plain IO afterwards. Something, however, goes wrong and only "See you soon" gets printed, putStrLn $ show v produces no output.

So the question is: how do I fix it and, most importantly, why doesn't it print anything?

Edit: thank you everyone for your answers, they help a lot.


1 Answers

In my humble opinion, monad transformers are easier to work with if you use the mtl typeclasses. This also leads to more general code since it doesn't tie you to any concrete data type. Also, I would recommend usually separating the "what to do" part from the "run" part. I've rewritten your code to hopefully demonstrate what I mean:

import System.Random
import Control.Monad.State

data GlobalState = GS { rng :: StdGen }

zeroState = GS { rng = mkStdGen 0 }

roll :: StdGen -> (Int,StdGen)
roll = randomR (1,6)

-- works with any concrete monad m that supplies IO and GlobalState state
foo :: (MonadIO m, MonadState GlobalState m) => m () 
foo = do
  (v,gen) <- gets (roll . rng)
  liftIO $ print v
  put $ GS gen

 -- commit to StateT here
 evalFoo :: IO ()
 evalFoo = evalStateT foo zeroState

The benefit is that foo is now reusable. For example, if we wanted to roll multiple times:

 evalFooN :: Int -> IO ()
 evalFooN n = evalStateT (replicateM_ n foo) zeroState
like image 144
user2297560 Avatar answered Dec 22 '25 12:12

user2297560



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!