haskell system.random.mwc随机整数

use*_*080 0 random haskell 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)}
Run Code Online (Sandbox Code Playgroud)

但我对System.Random.MWC感到困惑.

kos*_*kus 5

首先,你不应该使用unsafePerformIO.生成随机数是具有副作用的操作,因此p :: Integer -> Integer对于Integer0给定数量的范围内生成随机的函数不是合适的类型.

以下是如何正确使用System.Random:

import System.Random

p :: Integer -> IO Integer
p n = randomRIO (0 , n)

main :: IO ()
main = do
  x <- p 30
  print x
Run Code Online (Sandbox Code Playgroud)

因为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
Run Code Online (Sandbox Code Playgroud)

关于在GHCi中这样做

在你的评论中,你说如果你在GHCi中做这样的事情,就像这样:

Prelude> import System.Random.MWC
Prelude System.Random.MWC> gen <- createSystemRandom 
Prelude System.Random.MWC> uniformR (0, 30) gen
27.823000834177332
Run Code Online (Sandbox Code Playgroud)

然后它看起来好像uniformR在生成浮点数,而不是整数.这是由于在Haskell中应用的重载数值类型的"默认",Haskell是Haskell语言的一个陌生和棘手的角落,可能有些令人困惑.类型uniformR是:

uniformR :: (Control.Monad.Primitive.PrimMonad m, Variate a) =>
            (a, a) -> Gen (Control.Monad.Primitive.PrimState m) -> m a
Run Code Online (Sandbox Code Playgroud)

在GHCi上下文中,PrimMonad将是IO,因此您可以将类型视为更简单:

uniformR :: Variate a => (a, a) -> GenIO -> IO a
Run Code Online (Sandbox Code Playgroud)

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

Prelude System.Random.MWC> uniformR (0, 30) gen :: IO Int
25
Run Code Online (Sandbox Code Playgroud)

明确指出你想要一个Int,而不是一个Double.