2011-09-18 15 views
5

Próbuję opracować losową liczbę "generator" w F #.Siła wielu ocen funkcji w F #

pomyślnie stworzył następującą funkcję:

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

To działa prawidłowo i generuje liczbę między 0 a 36.

Jednak Próbuję utworzyć funkcję, która działa ta funkcja kilka razy .

Próbowałem następujące

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

Jednakże, otrzymuję tylko pojedynczy wynik, jak draw oceniana jest tylko raz w do zrozumienia.

W jaki sposób mogę wymusić wielokrotne wykonywanie funkcji draw?

Odpowiedz

8

Problem dotyczy typu losowego. Wykorzystuje on czas komputera do generowania materiału siewnego, a następnie generowania liczb losowych. Ponieważ praktycznie czas połączeń jest identyczny, generowany jest ten sam materiał siewny, a więc zwracane są również te same liczby.

To rozwiąże problem:

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

, a następnie:

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

OK, dzięki, ale nie rozumiem, używając twojego rozwiązania, dlaczego nadal nie mam tego samego problemu z nasionami? – SRKX

+0

Podczas wywoływania konstruktora losowego generowane jest ziarno w oparciu o aktualny czas komputera. Następnie każde wywołanie metody Next generuje nowy seed * na podstawie poprzedniego seed *, a nie na podstawie czasu.Ponieważ nie zależy już od czasu, nie ma znaczenia, że ​​połączenia są wykonywane w tym samym czasie. –

+2

@SRKK: Możesz chcieć dodać rysunek 'printfn" nazywany "' jako pierwszą linią 'draw' body, aby zobaczyć, co się dzieje: zobaczysz tylko jedno wyjście. Twoja funkcja "draw" zwróciła liczby całkowite, podczas gdy jedna w odpowiedzi zwraca anonimową funkcję z podpisem '(unit -> int)', która faktycznie jest wywoływana w ramach rozumienia listy. Ta anonimowa funkcja przechwytuje wartość 'rand' w zamknięcie,' rand' zostaje zaszczepione tylko raz. –

6

Dodanie tego, aby pomóc wyjaśnić odpowiedź Ramona.

Ten kod wykorzystuje funkcję lambda.

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

Może być łatwiej zrozumieć, co się dzieje, jeśli nazwiesz funkcję lambda.

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

Do losowania zmiennych przypisywana jest funkcja next. Możesz przenieść rand i następny poza zakres losowania, aby zobaczyć zadanie bezpośrednio.

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

Widać z powyższego kodu, który w odpowiedzi Ramona nowy Losowe nazywa się tylko raz, gdy jest on nazywany wiele razy w przykładzie SRKX użytkownika.

Jak wspomniano przez Ramon Random generuje sekwencję liczb na podstawie losowego materiału siewnego. Zawsze będzie generował tę samą sekwencję liczb, jeśli użyjesz tego samego nasienia. Możesz przekazać losowo ziarno takie jak to new Random(2). Jeśli nie przekażesz jej wartości, użyje aktualnego czasu. Więc jeśli wywołasz nowe Losowe wiele razy z rzędu bez nasion, najprawdopodobniej będziesz miał to samo nasiono (ponieważ czas się nie zmienił). Jeśli materiał siewny nie ulegnie zmianie, pierwsza losowa liczba sekwencji będzie zawsze taka sama. Jeśli spróbujesz oryginalnego kodu SRKX i wywołasz multipleDraws z wystarczająco dużą liczbą, to czas zmieni się podczas pętli, a otrzymasz sekwencję liczb, która zmienia się co jakiś czas.

+0

Dzięki za dodatkowe wyjaśnienie! czyni to jeszcze bardziej przejrzystym. – SRKX