I'm not sure what I want to accomplish is sane or not (please be nice). But i had an idea for a small game, the game will need to have some state and the state is updated with some random component (otherwise it would be kind of boring). Seeing as the StdGen is also some kind of state i started modelling my program like this
import Control.Monad.State
import qualified System.Random as R
type Rng = StateT StdGen IO
random :: (Random a) => Rng a
random = state R.random
randoms :: (Random a) => Int -> Rng [a]
randoms n = replicateM n random
type GameS = [Int]-- not important right now
type Game = StateT GameS Rng
mainGame :: Game ()
mainGame = do
s <- gets
n <- lift $ randoms 10 :: (Rng [Int])
put s ++ n
mainRng :: Rng ()
mainRng = do
liftIO $ "Inside Rng!"
-- here do stuff that has to do with game setup and so on dependent on rng
runStateT mainGame [1,2,3,4]
main :: IO ()
main = do
g <- R.newStdGen
runStateT mainRng g
Alright that worked! So let's try and hide some of our details behind a newtype.
-- change type aliases for Game and Rng to newtype
newtype Rng a {
runR :: StateT R.StdGen IO a
} deriving (Applicative, Functor, Monad, MonadIO, MonadState R.StdGen)
newtype Game a {
runG :: StateT GameS Rng a
} deriving (Applicative, Functor, Monad, MonadIO, MonadState GameS)
-- and create a expose newRun functions
runRng :: Rng a -> IO (a, R.StdGen)
runRng k = do
g <- R.newStdGen
runStateT (runR k) g
runGame :: Game a -> Rng (a, GameS)
runGame k = let initial = [1,2,3]
in runStateT (runG k) initial
-- mainGame as before
mainGame :: Game ()
mainGame = do
liftIO $ print "Inside game"
s <- gets
n <- lift $ randoms 10 :: (Rng [Int])
put s ++ n
main :: IO ()
main = do
final <- runRng $ do
liftIO $ print "Inside rng moand"
runGame mainGame
print $ show final
This works to a point. Inside mainGame
i can do liftIO and all the state operations except when i try to lift
to get some random numbers i get a error couldn't match type 't0 Rng' with 'Game'
Do i somehow need to implement MonadTrans
for my Game
and Rng
types?
Any help with thid would be great!