Question

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)))
Was it helpful?

Solution

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.

OTHER TIPS

Try:

module Main where
import Data.IORef
import Control.Monad
import Data.Tuple(fst,snd)

randomGen :: Int -> (Int, Int)
randomGen x = (x,x+1)

getRandom :: IO Int -> IO (Int,Int)
getRandom x = do
    y <- x
    seed <- newIORef y
    liftM randomGen $ readIORef seed

At which point, use liftM fst on the output of getRandom to get the random number and liftM snd to get the seed for the next call... Oh and btw System.Random has randoms to generate an infinite list of random numbers (or anything else of Random instance). No point in reinventing the wheel.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top