Следующая программа завершается корректно:Является ли mapM в Haskell строгим? Почему эта программа получает переполнение стека?
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..5000]
main = do
randomInts <- randomList
print $ take 5 randomInts
Продолжительность:
$ runhaskell test.hs
[26156,7258,29057,40002,26339]
Однако, подавая его с бесконечным списком, программа никогда не заканчивается, и при компиляции, в конечном счете, дает ошибку переполнения стека!
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..]
main = do
randomInts <- randomList
print $ take 5 randomInts
Бег,
$ ./test
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
Я ожидал, что программа лениво оценивать getStdRandom
каждый раз, когда я выбираю элемент из списка, отделка после делать это в 5 раз. Почему он пытается оценить весь список?
Спасибо.
Есть ли лучший способ получить бесконечный список случайных чисел? Я хочу передать этот список в чистую функцию.
EDIT: Некоторые более чтения показали, что функция
randomList r = do g <- getStdGen
return $ randomRs r g
является то, что я искал.
EDIT2: после прочтения ответа от компании Camcann я понял, что getStdGen
получает новое семя при каждом звонке. Вместо этого лучше использовать эту функцию в качестве простого однократного случайного генератора списка:
import System.Random
randomList :: Random a => a -> a -> IO [a]
randomList r g = do s <- newStdGen
return $ randomRs (r,g) s
main = do r <- randomList 0 (50::Int)
print $ take 5 r
Но я до сих пор не понимаю, почему мой mapM
вызов не прекращается. Очевидно, не относится к случайным числам, но что-то делать с mapM
.
Например, я обнаружил, что следующий также не прекращается:
randomList = mapM (\_->return 0) [0..]
main = do
randomInts <- randomList
print $ take 50000 randomInts
Что это дает? Кстати, IMHO, вышеуказанная функция randomInts
должна быть в System.Random
. Очень удобно иметь очень генерировать случайный список в монаде IO и передавать его в чистую функцию, когда это необходимо, я не понимаю, почему это не должно быть в стандартной библиотеке.
О, и в качестве дополнения к моему ответу: вы можете написать более общую версию 'randomInts' как просто' \ r -> fmap (randomRs r) getStdGen'. Это имеет тип '(Random a) => (a, a) -> IO [a]', другими словами, он генерирует список случайных значений в данном диапазоне для любого типа, который является экземпляром «Random». –
Еще лучше, спасибо. – Steve
Полагаю, поэтому моя функция randomList даже не должна быть в стандартной библиотеке, если она может быть такой короткой, но мальчик не является очевидным, как написать это для newb;) Поэтому я все еще думаю, что это должно быть там для удобства .. – Steve