haskell system.random.mwc随机整数

时间:2014-02-14 21:33:45

标签: haskell random integer

我想使用库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感到困惑。

1 个答案:

答案 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中执行此操作

在你的评论中,你说如果你在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类的任何实例,结果类型可以是VariateVariate类在mwc-random包中定义了各种实例。当您在GHCi中输入此内容时,没有类型签名或上下文会限制a。那么GHC应该选择多少选项中的哪一个?这就是违约所规定的。 Haskell中的标准默认顺序是Integer,然后是DoubleVariate Integer没有实例,因此选择了Variate Double的实例。如果两个实例都不存在,则会报告类型错误。您始终可以通过提供类型注释来覆盖默认值。所以在这里,你可以做到

Prelude System.Random.MWC> uniformR (0, 30) gen :: IO Int
25

明确指出您需要Int,而不是Double