【问题标题】:Pure pseudo-random generators for Haskell with a nice API?带有漂亮 API 的 Haskell 的纯伪随机生成器?
【发布时间】:2012-01-08 09:22:00
【问题描述】:

对于纯伪随机生成器(统一双精度),推荐的 Haskell 包有哪些?

我首先对方便的 API 很感兴趣,速度也会很好。

也许是 mwc-random?

【问题讨论】:

    标签: haskell random


    【解决方案1】:

    我喜欢mersenne-random-pure64 包。例如,您可以像这样使用它从种子值生成无限的惰性随机双精度流:

    import Data.Word (Word64)
    import Data.List (unfoldr)
    import System.Random.Mersenne.Pure64
    
    randomStream :: (PureMT -> (a, PureMT)) -> PureMT -> [a]
    randomStream rndstep g = unfoldr (Just . rndstep) g
    
    toStream :: Word64 -> [Double]
    toStream seed = randomStream randomDouble $ pureMT seed
    
    main = print . take 10 $ toStream 42
    

    使用 System.Random(随机)

    您可以使用内置的 randoms 函数获得类似的输出,该函数更短且更通用(感谢 ehird 指出):

    import System.Random (randoms)
    import System.Random.Mersenne.Pure64 (pureMT)
    
    main = print . take 10 $ randomdoubles where
      randomdoubles :: [Double]
      randomdoubles = randoms $ pureMT 42
    

    使其成为 MonadRandom 的实例

    在阅读了MonadRandom 之后,我很好奇如何让PureMT 作为它的一个实例来工作。开箱即用它不起作用,因为PureMT 没有实例化RandomGensplit 函数。使其工作的一种方法是将PureMT 包装在newtype 中并为RandomGen 类型类编写一个自定义split 实例,其中存在一个默认的MonadRandom 实例。

    import Control.Monad.Random
    import System.Random.Mersenne.Pure64
    
    getTenRandomDoubles :: Rand MyPureMT [Double]
    getTenRandomDoubles = getRandoms >>= return . take 10
    
    main = print $ evalRand getTenRandomDoubles g
      where g = MyPureMT $ pureMT 42
    
    
    newtype MyPureMT = MyPureMT { unMyPureMT :: PureMT }
    myPureMT = MyPureMT . pureMT
    
    instance RandomGen MyPureMT where
      next  = nextMyPureMT
      split = splitMyPureMT
    
    splitMyPureMT :: MyPureMT -> (MyPureMT, MyPureMT)
    splitMyPureMT (MyPureMT g) = (myPureMT s, myPureMT s') where
      (s',g'') = randomWord64 g'
      (s ,g' ) = randomWord64 g
    
    nextMyPureMT (MyPureMT g) = (s, MyPureMT g') where
      (s, g') = randomInt g
    

    【讨论】:

    • 您可以对任何RandomGen(其中PureMT 是一个实例)执行此操作,randoms :: (RandomGen g, Random a) => g -> [a]
    • @ehird 哦,不知道randoms!更新了我的答案
    • 还有monad-mersenne-randomhackage.haskell.org/package/monad-mersenne-random建立在mersenne-random-pure64之上。它有一个很好的特性,它允许在恒定的内存空间中运行一元迭代(请参阅这个问题:stackoverflow.com/questions/3236442)。
    • @sastin 感谢您指出相关问题和monad-mersenne-random,给了我一些新的见解!
    【解决方案2】:

    标准的System.Random 有一个纯接口。我建议将其包装在 State g 中(对于您正在使用的任何生成器 g )以避免线程化状态; state 函数可以轻松地将 next 之类的函数转换为有状态的操作:

    next :: (RandomGen g) => g -> (Int, g)
    state :: (s -> (a, s)) -> State s a
    state next :: (RandomGen g) => State g Int
    

    MonadRandom 包基于State g 接口,并为生成器函数预先编写了包装器;我认为它相当受欢迎。

    请注意,您仍然可以使用这个纯接口on the global RNG 运行操作。 MonadRandom 有 evalRandIO 用于此目的。

    我认为您可以编写一个(孤儿)RandomGen 实例以将 mwc-random 与这些一起使用。

    【讨论】:

    • @ehird 什么是 IO 免费的随机源,可以保持它的纯净? ECC?
    • @JFritsch:记住,pure 不仅仅意味着没有 IO。纯函数必须总是在给定相同参数的情况下返回相同的结果。唯一的“随机性来源”是生成器或 seed(类型签名中的g)。
    • @JFritsch:没有 PRNG 为每个号码咨询外部来源;你只是从那里得到种子。您可以从种子中创建 StdGen 类型的值(RandomGen 的实例),并且 IO 中有一个全局生成器,大概是从外部来源播种的。
    • @ehird 对于 P RNG,您当然是对的。否则“不”有点强:D sqrtech.com。良好的随机性是 web2.0 世界中的一个问题,IO 在其中扮演着重要角色。
    【解决方案3】:

    cprng-aes 包是一个特别好的包,它具有纯接口,也适用于加密应用程序并保持高性能。

    它提供了两个接口:一个使用 System.Random 中的类型类的确定性纯接口,以及一个使用 Crypto-API 包中的类型类的强 IO 接口。

    附带说明:我通常更喜欢 mersenne-random 包而不是 mwc-random。他们使用原始的 Mersenne Twister 算法,在我的基准测试中,其性能大大优于 mwc-random。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-18
      • 1970-01-01
      • 2020-09-24
      相关资源
      最近更新 更多