Consapevole del fatto che quando qualcosa sembra troppo bello per essere vero di solito è, ho pensato che avrei posto questa domanda per eliminare eventualmente tutti i gremlins. Ho esaminato i pochi thread correlati che ho potuto trovare, ma la mia domanda rimane ancora.Qualcosa che non va con il mio Fisher-Yates shuffle?
Sono relativamente nuovo per Haskell, e nella mia sperimentazione ho codificato un rimescolamento base di Fisher-Yates come mostrato di seguito.
shuffle :: RandomGen g => [a] -> g -> ([a],g)
shuffle [] g0 = ([],g0)
shuffle [x] g0 = ([x],g0)
shuffle xs g0 = (x:newtail,g2)
where (i,g1) = randomR (0, length $ tail xs) g0
(xs1,x:xs2) = splitAt i xs
(newtail,g2) = shuffle (xs1++xs2) g1
Questa implementazione del corso utilizza la memoria beaucoup per grandi liste, ma è veloce - sul mio portatile 5s medio per 30M interi vs. Std C++ casuale a 2.3s). In effetti, è molto più veloce di altre implementazioni Haskell trovato altrove. (Ad esempio, http://www.haskell.org/haskellwiki/Random_shuffle)
Dato altri shuffle Haskell che ho visto sono entrambi più complicati e più lenti, mi chiedo se la velocità/semplicità sia semplicemente la mia ricompensa per essere un porco menefreghista, o se mi sono perso qualche dettaglio minuscolo ma cruciale che rende distorto il mio algoritmo. Non ho testato estesamente, ma un aspetto preliminare sembra mostrare una distribuzione uniforme delle permutazioni.
Apprezzerei la valutazione di più occhi con più esperienza Haskell e/o mischia. Mille grazie in anticipo a tutti coloro che hanno il tempo di rispondere.
Dato che questo calcola la lunghezza dell'elenco a ogni iterazione, trovo che i numeri delle prestazioni specificati siano difficili da credere. È un algoritmo O (n^2). – Carl
Stai forse cronometrando l'algoritmo senza forzare realmente l'intero risultato da valutare? –
Mostra il codice temporale. Un completo shuffle di 30 milioni di 'Int con quel codice impiega giorni per essere completato. –