I'm trying to make a simple random number generator in Haskell using IORef now to store mutable variables. The idea is that I can initialise the seed, and then generate numbers based on the seed, and store the new seed for the next random int.
The full error I'm getting is:
random2.hs:9:17:
Couldn't match type `IO Int' with `Int'
Expected type: IO (IORef Integer)
-> (IORef Integer -> IO Int) -> Int
Actual type: IO (IORef Integer)
-> (IORef Integer -> IO Int) -> IO Int
In a stmt of a 'do' block: seed <- newIORef 7
In the expression:
do { seed <- newIORef 7;
randomGen (readIORef seed) }
In an equation for `getRandom':
getRandom
= do { seed <- newIORef 7;
randomGen (readIORef seed) }
random2.hs:10:17:
Couldn't match type `(,) Int' with `IO'
Expected type: IO Int
Actual type: (Int, Int)
In the return type of a call of `randomGen'
In a stmt of a 'do' block: randomGen (readIORef seed)
In the expression:
do { seed <- newIORef 7;
randomGen (readIORef seed) }
random2.hs:10:28:
Couldn't match expected type `Int' with actual type `IO Integer'
In the return type of a call of `readIORef'
In the first argument of `randomGen', namely `(readIORef seed)'
In a stmt of a 'do' block: randomGen (readIORef seed)
Failed, modules loaded: none.
I don't understand how it can not be matching the type - I'm explicit that the randomGen takes/returns an Int. Here's my code:
module Main where
import Data.IORef
randomGen :: Int -> (Int, Int)
randomGen x = (x,x+1)
getRandom :: Int
getRandom = do
seed <- newIORef 7
randomGen (readIORef seed)
Any idea what's going on here?
Thanks,
Updated code:
module Main where
import Data.IORef
import Control.Monad
randomGen :: Int -> (Int, Int)
randomGen x = (x,x+1)
getRandom :: IO Int
getRandom = do
seed <- newIORef 7
liftM (fst (randomGen (readIORef seed)))
The types IO Int
and Int
are entirely different in Haskell. This applies to any other type of that form, like Maybe Int
or Either String Int
. This is part of Haskell's type system design that makes it so powerful. You can think of anything in this form as a sort of container, it's parametrized over that type. Therefore you can do something like
getRandom :: IO Int
getRandom = do
seed <- newIORef 7 -- IO (IORef Int)
g <- readIORef seed -- IO Int
let (x, newG) = randomGen g -- (Int, Int)
writeIORef seed newG -- IO ()
return x -- IO Int
However, this will always return the same value since the seed is discarded after every call. I'm curious as to why you want to take this approach to generating random numbers at all, since there is such a nice API in the MonadRandom package. See this answer I wrote a while back for an example of how to use the Rand
monad, and this answer for a bit more of an in depth explanation of how it works.