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?
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
).
unknown = unsafePerformIO randomIO
is actually safe if compiler will evaluate body of unknown
only once. But I'm pretty sure that compiler have rights to inline it and/or calculate many times. –
Supplicant 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?
Aside from performance (no risk) or stability (small risk), consider also the fact that you are writing non-canonical Haskell for no good reason. Your code will be difficult for anyone else to maintain if you take this approach.
© 2022 - 2024 — McMap. All rights reserved.
random
orrandomR
in pure code. – CallboardunsafeInterleaveIO
but nothing random is pure! – SabrinaIO
monad anyway. – HeimrunST
, there's just no easy way to enforce it the wayST
does. The random values are still "locally" impure, though. – BuiltinunsafePerformIO
at all. Why do you say that you must only use pure functions? – ErelongRand
monad or itsRandT
transformer. This way you can make your code pure, without needing to useIO
or to carry the random state around all the time. – Rappee