I am trying to generate a random number using randomR but it is showing an error which I am not getting.
My code:
randomMessage :: IO String
randomMessage = do
index<-fst $ randomR (0,9) (mkStdGen 66)
--let index = randomRIO (1,10)
return ("This is message " show index)
Error:
app\Main.hs:63:18: error:
* No instance for (Random (IO a0)) arising from a use of `randomR'
* In the second argument of `($)', namely
`randomR (0, 9) (mkStdGen 66)'
In a stmt of a 'do' block:
index <- fst $ randomR (0, 9) (mkStdGen 66)
In the expression:
do index <- fst $ randomR (0, 9) (mkStdGen 66)
return ("This is message " show index)
index<-fst $ randomR (0,9) (mkStdGen 66)
^^^^^^^
Kindly let me know the solution
CodePudding user response:
randomIO
returns an IO
action from which you can extract a value.
randomMessage :: IO String
randomMessage = do
index <- randomRIO (1,10::Int)
return ("This is message " show index)
A type annotation is necessary to indicate what type of value index
will be, so that the correct Show
instance may be selected.
randomR
returns a tuple consisting of a random value and a new random number generator.
randomMessage :: IO String
randomMessage = do
let index = fst $ randomR (0,9 :: Int) (mkStdGen 66)
return ("This is message " show index)
This "works", but it won't be very random, as the exact same seed is used for every call. (There's also no reason for it to return an IO action. randomR
is pure, the idea being that its return value contains what you need to generate another random number.) You can use getStdGen
, but that's still the same random number generator each time you call the function.
randomMessage :: IO String
randomMessage = do
(index, _) <- randomR (0,9 :: Int) <$> getStdGen
return ("This is message " show index)
To fix this, you need to use setStdGen
on the other value in the tuple produced by randomR
.
randomMessage :: IO String
randomMessage = do
(index, nextGen) <- randomR (0,9 :: Int) <$> getStdGen
setStdGen nextGen
return ("This is message " show index)
(If I understand the definition of randomIO
correctly, this is essentially what it does: uses randomR
to generate a new number and update the system generator. One important difference: it gets a random number and updates the system generator atomically, so that anyone else trying to use the system generator will use the generator produced here by randomR
, not the same one that getStdGen
initially provided.)