我想使用库System.Random.MWC生成范围(0,30)中的随机整数。我可以使用库System.Random来执行此操作:
import System.Environment
import System.IO.Unsafe
import System.Random
p :: Integer -> Integer
p n = unsafePerformIO (getStdRandom (randomR (0 , n)))
main :: IO()
main = do
print $! (p 30)}
但我对System.Random.MWC感到困惑。
答案 0 :(得分:5)
首先,您不应该使用unsafePerformIO
。生成随机数是一种具有副作用的操作,因此p :: Integer -> Integer
不适合在Integer
到给定数量范围内生成随机0
的函数。 / p>
以下是使用System.Random
:
import System.Random
p :: Integer -> IO Integer
p n = randomRIO (0 , n)
main :: IO ()
main = do
x <- p 30
print x
对于mwc-random
,类型Integer
没有生成器,但Int
有一个生成器,可能会为您提供足够大的范围。这是一个例子:
import System.Random.MWC
p :: Int -> GenIO -> IO Int
p n gen = uniformR (0, n) gen
main :: IO ()
main = do
gen <- createSystemRandom
x <- p 30 gen
print x
在你的评论中,你说如果你在GHCi中做这样的事情,就像这样:
Prelude> import System.Random.MWC
Prelude System.Random.MWC> gen <- createSystemRandom
Prelude System.Random.MWC> uniformR (0, 30) gen
27.823000834177332
然后看起来好像uniformR
正在生成浮点数,而不是整数。这是由于在Haskell中应用的重载数值类型的“默认”,Haskell是Haskell语言的一个陌生和棘手的角落,可能有些令人困惑。 uniformR
的类型为:
uniformR :: (Control.Monad.Primitive.PrimMonad m, Variate a) =>
(a, a) -> Gen (Control.Monad.Primitive.PrimState m) -> m a
在GHCi环境中,PrimMonad
将为IO
,因此您可以将类型视为更简单:
uniformR :: Variate a => (a, a) -> GenIO -> IO a
因此,对于IO a
类的任何实例,结果类型可以是Variate
。 Variate
类在mwc-random
包中定义了各种实例。当您在GHCi中输入此内容时,没有类型签名或上下文会限制a
。那么GHC应该选择多少选项中的哪一个?这就是违约所规定的。 Haskell中的标准默认顺序是Integer
,然后是Double
。 Variate Integer
没有实例,因此选择了Variate Double
的实例。如果两个实例都不存在,则会报告类型错误。您始终可以通过提供类型注释来覆盖默认值。所以在这里,你可以做到
Prelude System.Random.MWC> uniformR (0, 30) gen :: IO Int
25
明确指出您需要Int
,而不是Double
。