Risks of using unsafeperformIO on randomIO

haskell, random, unsafe-perform-io

Solution

Any use of `unsafePerformIO` should be justified by a proof that the resulting value is still pure. The rigour of the proof is up to you and the importance of the work. For example, this pathetic use `unsafePerformIO` and `randomIO` should be safe, because you can prove that when `slowTrue` returns anything, it will return `True`.

import System.Random
import System.IO.Unsafe
import Data.Int

slowTrue = unsafePerformIO $ go
  where
    go = do
        x1 <- randomIO
        x2 <- randomIO
        if ((x1 :: Int16) == x2) then return True else go

The following tempting definition of a global, possibly random variables is not safe:

rand :: Bool -> Int
rand True = unsafePerformIO randomIO 
rand False = 0

The problem is that the same expression will now yield different values:

main = do
    print (rand True)
    print (rand True)

prints here:

-7203223557365007318
-7726744474749938542

(at least when compiled without optimizations – but that just stresses the fragility of inappropriate use of `unsafePerformIO`).

Problem

I am creating a Haskell application that generates a random number on an infinite loop (only when requested by a client). However, I should only use pure functions for that purpose. Is it safe to wrap `randomIO` with `unsafeperformIO` without any drastic stability or performance risk?

Original source