How can I generate a random number in Haskell from a range (a, b) without using any seed?
The function should return an Int and not an IO Int. I have a function X t
I used SipHash for that purpose
import Data.ByteArray.Hash
import Data.ByteString (pack, cons)
import Data.Word (Word8, Word64)
random :: Word64 -> Word64 -> [Word8] -> Double
random a b cs = (subtract 1) . (/(2**63)) . read . drop 8 . show $ sipHash (SipKey a b) (pack cs)
the read and drop 8 and show serve the purpose to drop a newtype that doesn’t (or didn’t when I implemented this) support any casting
now you want an Int in a range. Integer is easier though:
random :: Word64 -> Word64 -> [Word8] -> (Integer, Integer) -> Integer
random a b cs (low,high) = let
span = high-low
rand = read . drop 8 . show $ sipHash (SipKey a b) (pack cs)
in (rand `mod` span) + low
of course, you’ll still get the same number for the same arguments every time, so you’ll need to vary them ie you still pass around arguments, just not returned values too. Whether that’s more convenient than a monad depends (for my purpose it was)
this is how I made sure arguments (specifically the [Word8] argument) would always be different:
foo bytes = doSomethingRandom bytes
bar bytes = map (\i -> foo (i:bytes)) [1..n]
baz bytes = doSomething (foo (0:bytes)) (bar (1:bytes))