强制对F#中的函数进行多次评估

时间:2011-09-18 21:14:29

标签: f#

我正在尝试在F#中开发一个随机数“生成器”。

我成功创建了以下功能:

let draw () =
    let rand = new Random()
    rand.Next(0,36)

这样可以正常工作,它会生成0到36之间的数字。

但是,我正在尝试创建一个多次运行此函数的函数。

我尝试了以下

let multipleDraws (n:int) =
    [for i in 1..n -> draw()]

但是,我只得到一个结果,因为draw在for comprehension中仅被评估一次。

如何强制多次执行draw功能?

2 个答案:

答案 0 :(得分:8)

问题在于随机类型。它使用计算机的时间生成种子,然后生成随机数。由于实际上调用的时间是相同的,因此生成相同的种子,因此也返回相同的数字。

这将解决您的问题:

let draw =
    let rand = new Random()
    fun () ->
    rand.Next(0,36)

然后:

let multipleDraws (n:int) =
    [for i in 1..n -> draw()]

答案 1 :(得分:6)

添加此内容以帮助解释Ramon的答案。

此代码使用lambda函数。

let draw =
    let rand = new Random()
    fun () ->
    rand.Next(0,36)

如果给lambda函数命名,可能更容易理解发生了什么。

let draw =
    let rand = new Random()
    let next() =
        rand.Next(0,36)
    next

接下来为变量draw赋值。您可以将rand和next移出绘图范围以直接查看赋值。

let rand = new Random()
let next() =
    rand.Next(0,36)
let draw = next

从上面的代码可以看出,在Ramon的回答中,新的Random只被调用一次,而在SRKX的例子中被多次调用。

如Ramon Random所述,基于随机种子生成一系列数字。如果使用相同的种子,它将始终生成相同的数字序列。您可以随机传递种子new Random(2)。如果您没有传递值,则使用当前时间。因此,如果你连续多次调用新的Random而没有种子,它很可能会有相同的种子(因为时间没有改变)。如果种子没有改变,那么序列的第一个随机数将始终相同。如果您尝试使用SRKX的原始代码并使用足够大的数字调用multipleDraws,那么时间将在循环期间发生变化,您将获得一系列经常更改的数字。