случайное поколение в список fsharp - PullRequest
5 голосов
/ 13 августа 2011

Я пытаюсь использовать 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 # интерактивный)

foo 0 50

При попытке создать список случайных троек, как этот

List.init 100 (fun index -> foo 0 50)

Я бы хотел, чтобы это был список из 100 рандомизированных троек , но вместо этого все они имеют одинаковое значение. Я вижу, что функция не зависит от индекса и, следовательно, не нуждается в пересчете, но я не уверен, как обойти это (я попытался представить индекс как неиспользуемую фиктивную переменную, также попытался ввести индекс как случайное семя, но не помогло)

Ответы [ 3 ]

14 голосов
/ 13 августа 2011

Вы предполагаете, что причина того, что ваш код не работает так, как вы этого хотите, заключается в том, что компилятор ошибочно применяет какое-то общее исключение подвыражений, что приводит к тому, что foo 0 50 оценивается только один раз.Это не вариант.Компилятор очень хорошо знает, что функции могут быть нечистыми и не будут выполнять оптимизации, которые порвались бы с нечистым кодом (если только не доказано, что конкретный код, который оптимизируется, является чистым).Так что вам не нужно беспокоиться о том, чтобы компилятор думал, что вы используете аргумент.

Проблема не в том, что foo 0 50 вызывается только один раз - он действительно вызывается 100 раз, как вы хотите,Проблема в том, что он возвращает одно и то же значение каждый из 100 раз, когда он вызывается.

Но зачем ему это делать, когда он возвращает разные значения при тестировании вручную?

Поскольку вы создаетеновый случайный объект каждый раз, когда вы звоните foo.Поскольку вы не предоставляете начальное значение этому случайному объекту, оно будет заполнено текущим системным временем.Поэтому, если вы вызываете функцию несколько раз, а между ними проходит некоторое время, она каждый раз будет возвращать разные значения.Однако, если вы вызовете его 100 раз за такой короткий промежуток времени, что системное время между ними не изменится, вы получите одно и то же значение 100 раз.

Таким образом, решение вашей проблемы заключается в повторном использованииодин и тот же случайный объект вместо создания нового каждый раз, когда вызывается foo.

11 голосов
/ 13 августа 2011

Попробуйте вместо этого.Он будет использовать один и тот же случайный объект без необходимости держать его в основной области видимости:

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 из нескольких потоков, вам нужно добавить несколькоблокировка на Далее.

3 голосов
/ 13 августа 2011

Дополнить ответ 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
...