我正在尝试使用F#生成随机三元组列表 - >两个随机数及其总和:
let foo minNum maxNum =
let rnd = System.Random()
let first = rnd.Next(minNum, maxNum)
let second = rnd.Next(minNum, maxNum)
let third = first + second
first, second, third
可以像这样调用并运行良好(总是给出一个新的随机数)(当使用F#interactive时)
foo 0 50
尝试生成像这样的随机三元组列表
List.init 100 (fun index -> foo 0 50)
我希望这是一个包含100个随机三元组的列表,但相反它们都会出现相同的值。我可以看到该函数不依赖于索引,因此不需要重新计算,但我不知道如何解决它(我尝试将索引作为未使用的虚拟变量引入,也尝试将索引作为一个引入随机种子,但没有帮助)
答案 0 :(得分:14)
您假设您的代码不能像您希望的那样工作的原因是编译器错误地应用了某种常见的子表达式消除,这导致foo 0 50
仅被评估一次。不是这种情况。编译器非常清楚函数可能是不纯的,并且不会执行会破坏不纯的代码的优化(除非可以证明优化的特定代码是纯的)。因此,您不必担心让编译器认为您正在使用该参数。
问题不在于foo 0 50
只被调用一次 - 它确实被称为100次。问题是它在100次调用时返回相同的值。
但是当你手动测试它时,为什么它会返回不同的值呢?
因为每次调用foo
时都会创建一个新的Random对象。由于您没有为该随机对象提供种子值,因此将使用当前系统时间播种。因此,如果您多次调用该函数并在其间传递一段时间,则每次都会返回不同的值。但是,如果你在如此短的时间内拨打它100次,系统时间不会改变,那么你将获得相同的值100次。
因此,您的问题的解决方案是重复使用相同的随机对象,而不是每次调用foo
时创建一个新的随机对象。
答案 1 :(得分:11)
试试这个。它将重用相同的随机对象,而不必在主范围内保留一个:
let foo =
let rnd = System.Random()
fun minNum maxNum ->
let first = rnd.Next(minNum, maxNum)
let second = rnd.Next(minNum, maxNum)
let third = first + second
first, second, third
另请注意,Next不是线程安全的,因此如果您打算从多个线程使用foo,则需要向Next添加一些锁定。
答案 2 :(得分:3)
用一些代码补充sepp2k答案:
let rnd = System.Random()
let foo minNum maxNum =
let first = rnd.Next(minNum, maxNum)
let second = rnd.Next(minNum, maxNum)
let third = first + second
first, second, third