我想学习Elm,目前我想创建一个随机列表,其中包含一个包含索引和随机数的元组。
我目前的方法是创建一个列表,并为每个元素创建一个随机值:
randomList =
List.map randomEntry (List.range 0 1000)
randomEntry index =
let
seed = Random.initialSeed index
randomResult = Random.step (Random.int 1 10) seed
in
(index, Tuple.first randomResult)
但这只会创造偶数。
为什么它总是创建偶数数字,这样做的正确方法是什么?
答案 0 :(得分:4)
奇怪 - 使用您的randomEntry
功能,第一个奇数号码开始显示直到53668,然后它的奇数一段时间。 REPL的一个例子:
> List.range 0 100000 |> List.map randomEntry |> List.filter (\(a,b) -> b % 2 /= 0) |> List.take 10
[(53668,35),(53669,87),(53670,1),(53671,15),(53672,29),(53673,43),(53674,57),(53675,71),(53676,85),(53677,99)]
: List ( Int, Int )
现在我无法告诉你为什么在这个范围内存在这种粘性(here's the source for the int
generator if you're curious),但希望我可以对榆树的随机性有所了解。
实际上没有办法使用标准计算技术(旁边的量子计算机)创建真正的随机数生成器,因此创建随机性的典型方法是提供一个获取种子值,返回伪随机数和下一个要使用的种子值。
这使得随机数生成可预测,因为您将始终获得相同的"随机数"同一种子的编号。
这就是为什么你总是得到相同的输入结果:你使用相同的种子值0到1000.此外,你忽略了下一个种子"值从step
函数返回,该函数作为元组的第二个值返回。
现在,在处理随机数生成器时,尽可能避免处理种子是一个很好的经验法则。您可以通过构建int
,list
等较小的生成器来编写生成器,而无需引用种子。
执行生成器的方式是从Random.generate
函数返回从update
生成的Cmd,这使得负责决定使用哪个种子到Elm Architecture(可能使用了一些)基于时间的种子),或者您可以使用上面已经完成的Random.step
传递种子。
所以,回到你原来的例子,如果你要编写一个生成器来返回一个特定大小的随机数列表,其中每个数字在一定范围内,它可能看起来像这样:
randomListGenerator : Int -> (Int, Int) -> Random.Generator (List Int)
randomListGenerator size (low, high) =
Random.list size (Random.int low high)
在REPL中使用step
执行此操作会显示如何使用它:
> initialSeed 0 |> step (randomListGenerator 20 (1, 10)) |> Tuple.first
[6,6,6,1,3,10,4,4,4,9,6,3,5,3,7,8,3,4,8,5] : List Int
您会看到这包含一些奇数,与您的初始示例不同。它与您的示例不同的事实是因为生成器返回下一个种子以使用每个连续步骤,而您的示例按顺序使用整数0到1000。我仍然没有解释你原来的问题,为什么有这么大的平均值使用你的原始输入,除了说它很奇怪。