Home > OS >  No instance for (Random (IO a0)) arising from a use of `randomR' in Haskell
No instance for (Random (IO a0)) arising from a use of `randomR' in Haskell

Time:01-22

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.)

  • Related