如何在Haskell中生成随机数组?

时间:2014-03-15 11:28:33

标签: haskell

如何使用Data.Array生成随机数组?

我有功能,它给了我一个随机数:

randomNumber :: (Random r) => r -> r -> IO r
randomNumber a b = getStdRandom (randomR (a,b))

然后我尝试使用Data.Array中的函数生成列表

assocs $ array (1,100) [(i,i) | i <- (randomNumber 1 10)]

我知道,randomNumber的类型是IO,是否有任何方法可以转换IO Int -> Int?或者我需要使用其他方法来获取随机列表?我应该在bind块中使用do运算符执行这些功能吗?

2 个答案:

答案 0 :(得分:11)

你应该使用函数从生成器生成纯粹的随机列表,然后使用getStdRandom

randomList :: Int -> Int -> IO [Int]
randomList a b = getStdGen >>= return . randomRs (a,b)

您需要的功能是randomRs。然后,您使用stdGen将生成器设置为getStdGen,然后就可以使用生成器。 函数randomList首先使用getStdGen获取标准生成器,然后将其传递给randomRs。请注意,randomList可以在不隐藏生成器参数的情况下重写:

randomList a b = getStdGen >>= \gen -> return (randomRs (a,b) gen)

答案 1 :(得分:5)

只要@ mariop的回答讲述列表而不是数组,我就会继续,并尝试更多地解释Haskell随机性的本质。

(如果您对理论不感兴趣,请跳至(tl; dr)部分)

首先,让我们为我们推测的功能选择一个签名。我认为你需要一个普通的数组(如在C或Java中),用连续的自然数字索引(如果我猜错了,请更正)。

如您所知,所有Haskell函数都是纯粹且确定的,因此每个函数必须始终为相同的参数返回相同的结果。当然,这不是随机的情况。解决方案是使用随机值,其中我们有生成器。生成器本身是一个复杂的函数,具有一个名为 seed 的内部隐藏状态,并且可以生成一个值和一个带有新种子的新生成器(然后可以生成一个新的(值,生成器)对和等等)。建立一个好的生成器,以便无法从之前的值(当我们不知道种子时)预测下一个值,因此它们对用户来说是随机的。

  

事实上,大多数语言中的所有主要随机实现都是   伪随机因为&#34; true&#34;随机(从中获取其值)   &#34;自然&#34;的来源随机性,称为 entropy ,如CPU温度)   计算上很昂贵。

Haskell中的所有所谓随机函数都以某种方式处理生成器。如果您查看Random类型类中的方法,它们将分为两组:

  1. 明确获取随机生成器的那些:randomRrandom等等。您可以使用mkStdRandom构建一个使用种子初始化的显式生成器(甚至可以创建自己的生成器)。

  2. 在IO monad中工作的那些:randomIOrandomRIO。他们实际上从环境中获取发电机&#34;携带&#34;在IO monad中(使用getStdRandom),并从第一组开始运行。

  3. 因此,我们可以用任何一种方式组织我们的功能:

    --Arguments are generator, array size, min and max bound
    generateArray :: (RangomGen g, Random r) => g -> Int -> r -> r -> Array Int r

    --Arguments are array size, min and max bound
    generateArray :: Random r => Int -> r -> r -> IO (Array Int r)

    因为Haskell是懒惰的,所以不需要制作一组固定的随机值 - 我们可以创建一个无限,并根据需要获取尽可能多的值。随机有界值的无限列表由randomRs函数生成。

    (TL; DR)

    如果数组是连续的,更简单的方法是从普通值列表而不是assocs(键,值)列表构建它:

    generateArray gen size min max =
        listArray (0, size - 1) $ randomRs (min, max) gen
    

    generateArray size min max =
        getStdGen >>= return . listArray (0, size - 1) . randomRs (min, max)