Elm 随机列表实现
Elm random list implementation
Elm 标准库提供 a function to generate random lists 可以正常工作。
通过查看 its implementation,我们可以看到该列表是以函数式样式构建的,即从末尾到开头。当生成了足够多的元素后,返回反向列表:
if n < 1 then
(List.reverse list, seed)
我想知道为什么我们需要反转此列表?有必要保证"correct"随机性吗?
可能是因为大多数随机生成器并不是真正随机的。如果你用相同的种子启动它们,你会得到相同的序列。如果您依赖这个事实进行测试,那么以相反的顺序返回序列可能会破坏您的测试。
这是假设大多数程序员希望生成的序列按列表顺序排列,即第一个项目将最先生成。我认为这是一个可能的假设。因此,值得在末尾反转列表,这样 api 就不那么令人惊讶了。
List.reverse
调用实际上将列表放回到生成时的顺序。
这里是相关函数的代码:
list : Int -> Generator a -> Generator (List a)
list n (Generator generate) =
Generator <| \seed ->
listHelp [] n generate seed
listHelp : List a -> Int -> (Seed -> (a,Seed)) -> Seed -> (List a, Seed)
listHelp list n generate seed =
if n < 1 then
(List.reverse list, seed)
else
let
(value, newSeed) =
generate seed
in
listHelp (value :: list) (n-1) generate newSeed
如果我们在概念上将种子的概念简化为 Int
,并假设我们有一个 returns (seed, seed + 1)
的生成器,您可以这样推理迭代,如果我们的初始种子是 1
(生成 5 个元素的列表):
listHelp [] 5 myGen 1 -- initial state
listHelp [1] 4 myGen 2
listHelp [2,1] 3 myGen 3
listHelp [3,2,1] 2 myGen 4
listHelp [4,3,2,1] 1 myGen 5
listHelp [5,4,3,2,1] 0 myGen 6
然后将最终输出列表反转为您 [1,2,3,4,5]
。
最终排序对函数的整体随机性没有任何影响,但如果您 运行 具有相同种子但请求不同列表大小的多个列表,它确实会为您提供可预测的结果.
考虑在最后一步中列表是否不是(假设initialSeed
是1
)。
List.head (list 5 (myGen initialSeed)) == Just 5
List.head (list 4 (myGen initialSeed)) == Just 4
由于所有这些 pseudo-randomness 都需要 Seed
作为输入,因此以可预测的方式推理事物比引入任意 re-ordering 更有意义使 list
不可预测。 List.reverse
修复输出并将其放回可预测的领域。
因为我们可以将单个值添加到列表中,而我们只能将列表附加到列表中。我们可以
append list [value]
然后我们就不必反转它了
http://package.elm-lang.org/packages/elm-lang/core/latest/List
Elm 标准库提供 a function to generate random lists 可以正常工作。 通过查看 its implementation,我们可以看到该列表是以函数式样式构建的,即从末尾到开头。当生成了足够多的元素后,返回反向列表:
if n < 1 then
(List.reverse list, seed)
我想知道为什么我们需要反转此列表?有必要保证"correct"随机性吗?
可能是因为大多数随机生成器并不是真正随机的。如果你用相同的种子启动它们,你会得到相同的序列。如果您依赖这个事实进行测试,那么以相反的顺序返回序列可能会破坏您的测试。
这是假设大多数程序员希望生成的序列按列表顺序排列,即第一个项目将最先生成。我认为这是一个可能的假设。因此,值得在末尾反转列表,这样 api 就不那么令人惊讶了。
List.reverse
调用实际上将列表放回到生成时的顺序。
这里是相关函数的代码:
list : Int -> Generator a -> Generator (List a)
list n (Generator generate) =
Generator <| \seed ->
listHelp [] n generate seed
listHelp : List a -> Int -> (Seed -> (a,Seed)) -> Seed -> (List a, Seed)
listHelp list n generate seed =
if n < 1 then
(List.reverse list, seed)
else
let
(value, newSeed) =
generate seed
in
listHelp (value :: list) (n-1) generate newSeed
如果我们在概念上将种子的概念简化为 Int
,并假设我们有一个 returns (seed, seed + 1)
的生成器,您可以这样推理迭代,如果我们的初始种子是 1
(生成 5 个元素的列表):
listHelp [] 5 myGen 1 -- initial state
listHelp [1] 4 myGen 2
listHelp [2,1] 3 myGen 3
listHelp [3,2,1] 2 myGen 4
listHelp [4,3,2,1] 1 myGen 5
listHelp [5,4,3,2,1] 0 myGen 6
然后将最终输出列表反转为您 [1,2,3,4,5]
。
最终排序对函数的整体随机性没有任何影响,但如果您 运行 具有相同种子但请求不同列表大小的多个列表,它确实会为您提供可预测的结果.
考虑在最后一步中列表是否不是(假设initialSeed
是1
)。
List.head (list 5 (myGen initialSeed)) == Just 5
List.head (list 4 (myGen initialSeed)) == Just 4
由于所有这些 pseudo-randomness 都需要 Seed
作为输入,因此以可预测的方式推理事物比引入任意 re-ordering 更有意义使 list
不可预测。 List.reverse
修复输出并将其放回可预测的领域。
因为我们可以将单个值添加到列表中,而我们只能将列表附加到列表中。我们可以
append list [value]
然后我们就不必反转它了
http://package.elm-lang.org/packages/elm-lang/core/latest/List