I am in the process of learning Haskell and to learn I want to generate a random Int type. I am confused because the following code works. Basically, I want an Int not an IO Int.
In ghci this works:
Prelude> import System.Random
Prelude System.Random> foo <- getStdRandom (randomR (1,1000000))
Prelude System.Random> fromIntegral foo :: Int
734077
Prelude System.Random> let bar = fromIntegral foo :: Int
Prelude System.Random> bar
734077
Prelude System.Random> :t bar
bar :: Int
So when I try to wrap this up with do it fails and I don't understand why.
randomInt = do
tmp <- getStdRandom (randomR (1,1000000))
fromIntegral tmp :: Int
The compiler produces the following:
Couldn't match expected type `IO b0' with actual type `Int'
In a stmt of a 'do' block: fromIntegral tmp :: Int
In the expression:
do { tmp <- getStdRandom (randomR (1, 1000000));
fromIntegral tmp :: Int }
In an equation for `randomInt':
randomInt
= do { tmp <- getStdRandom (randomR (1, 1000000));
fromIntegral tmp :: Int }
Failed, modules loaded: none.
I am new to Haskell, so if there is a better way to generate a random Int without do that would be preferred.
So my question is, why does my function not work and is there a better way to get a random Int.
The simple answer is that you can't generate random numbers without invoking some amount of IO. Whenever you get the standard generator, you have to interact with the host operating system and it makes a new seed. Because of this, there is non-determinism with any function that generates random numbers (the function returns different values for the same inputs). It would be like wanting to be able to get input from STDIN from the user without it being in the IO monad.
Instead, you have a few options. You can write all your code that depends on a randomly generated value as pure functions and only perform the IO to get the standard generator in
main
or some similar function, or you can use the MonadRandom package that gives you a pre-built monad for managing random values. Since most every pure function inSystem.Random
takes a generator and returns a tuple containing the random value and a new generator, theRand
monad abstracts this pattern out so that you don't have to worry about it. You can end up writing code likeThere's also an accompanying monad transformer, but I'd hold off on that until you have a good grasp on monads themselves. Compare this code to using
System.Random
:Here we have to manually have to manage the state of the generator and we don't get the handy do-notation that makes our order of execution more clear (laziness helps in the second case, but it makes it more confusing). Manually managing this state is boring, tedious, and error prone. The
Rand
monad makes everything much easier, more clear, and reduces the chance for bugs. This is usually the preferred way to do random number generation in Haskell.It is worth mentioning that you can actually "unwrap" an
IO a
value to just ana
value, but you should not use this unless you are 100% sure you know what you're doing. There is a function calledunsafePerformIO
, and as the name suggests it is not safe to use. It exists in Haskell mainly for when you are interfacing with the FFI, such as with a C DLL. Any foreign function is presumed to performIO
by default, but if you know with absolute certainty that the function you're calling has no side effects, then it's safe to useunsafePerformIO
. Any other time is just a bad idea, it can lead to some really strange behaviors in your code that are virtually impossible to track down.I think the above is slightly misleading. If you use the state monad then you can do something like this:
See here for an extended example of usage:Markov Chain Monte Carlo