2016-11-07 2 views
1

У меня есть эта функция, которая выбирает 4 цвета randoms и составляет ее список. По крайней мере я хочу это слишком .:F # System.Random в рекурсивной функции делает забавные вещи

let theList = [Red;Green;Yellow;Purple;White;Black] 
let rec a x = 
    let rnd = System.Random() 
    match x with 
    |0 -> [] 
    |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1)) 

Проблема заключается в том, хотя он выбирает случайный цвет каждый раз, когда я запустить FUNKTION тогда он всегда выбирает один и тот же цвет для всего списка. [Красный, Красный, Красный, Красный] или [Зеленый, Зеленый, Зеленый, Зеленый] и т. Д.

Это тайна для меня, как она может достигать одного цвета каждый раз, когда она делает рекурсивный вызов.

Если я использую случайный метод в цикле for, то проблем нет.

Может кто-нибудь объяснить мне, что здесь происходит?

+3

Переведите вызов 'System.Random()' из функции, и он будет работать. Я напишу длинный ответ, объясняющий, почему. – rmunn

+1

Возможный дубликат [Получить случайные числа в F #] (http://stackoverflow.com/questions/37898225/get-random-numbers-in-f) –

ответ

4

Переведите ваш System.Random() вызов функции, и он будет работать. То, что вы делаете:

let rec a x = 
    let rnd = System.Random() 
    // ... Some code that calls rnd.Next() once, then recurses 

Каждый раз, когда вы рекурсию, вы создаете новый экземпляр System.Random и назначение его rnd. Это означает, что вы используете конструктор по умолчанию System.Random и its documentation предупреждает, что:

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

То, что вы действительно хотите, чтобы создать единый Random экземпляр, а затем использовать его метод .Next() неоднократно. Один из способов будет двигаться вызов System.Random() конструктора за пределами функции:

let theList = [Red;Green;Yellow;Purple;White;Black] 
let rnd = System.Random() 
let rec a x =  
    match x with 
    |0 -> [] 
    |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1)) 

Другой способ, если вы не хотите, чтобы выставить rnd имя для внешнего кода, было бы превратить a в «внутренний» функция, которая вложена внутри внешней функции (в следующем примере, doit является внешняя функция):

let theList = [Red;Green;Yellow;Purple;White;Black] 
let doit x = 
    let rnd = System.Random() 
    let rec a x = 
     match x with 
     |0 -> [] 
     |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1)) 
    a x 

Оба они должны производить действительно случайные (ну, псевдослучайные) результаты, которые вы ожидали.

+0

Большое вам спасибо! – Nulle

Смежные вопросы