Các chương trình sau đây chấm dứt một cách chính xác:Bản đồM trong Haskell có nghiêm ngặt không? Tại sao chương trình này bị tràn ngăn xếp?
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..5000]
main = do
randomInts <- randomList
print $ take 5 randomInts
Chạy:
$ runhaskell test.hs
[26156,7258,29057,40002,26339]
Tuy nhiên, cho ăn nó với một danh sách vô hạn, chương trình không bao giờ chấm dứt, và khi biên soạn, cuối cùng đưa ra một lỗi stack overflow!
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..]
main = do
randomInts <- randomList
print $ take 5 randomInts
chạy,
$ ./test
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
tôi mong đợi chương trình để uể oải đánh giá getStdRandom
mỗi khi tôi chọn một mục ra khỏi danh sách, hoàn thiện sau khi làm như vậy 5 lần. Tại sao nó cố gắng để đánh giá toàn bộ danh sách?
Cảm ơn.
Có cách nào tốt hơn để có danh sách số ngẫu nhiên vô hạn không? Tôi muốn chuyển danh sách này thành một hàm thuần túy.
EDIT: Một số đọc nhiều tiết lộ rằng chức năng
randomList r = do g <- getStdGen
return $ randomRs r g
là những gì tôi đang tìm kiếm.
EDIT2: sau khi đọc câu trả lời của camccann, tôi nhận thấy rằng getStdGen
đang nhận được hạt giống mới trên mọi cuộc gọi. Thay vào đó, tốt hơn để sử dụng chức năng này như một one-shot phát danh sách ngẫu nhiên đơn giản:
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
Nhưng tôi vẫn không hiểu tại sao mapM
cuộc gọi của tôi đã không chấm dứt. Rõ ràng là không liên quan đến các số ngẫu nhiên, nhưng có thể liên quan đến mapM
.
Ví dụ, tôi thấy rằng những điều sau đây cũng không chấm dứt:
randomList = mapM (\_->return 0) [0..]
main = do
randomInts <- randomList
print $ take 50000 randomInts
gì cho? Nhân tiện, IMHO, chức năng trên randomInts
phải ở trong System.Random
. Nó cực kỳ thuận tiện để có thể rất chỉ đơn giản là tạo một danh sách ngẫu nhiên trong đơn nguyên IO và chuyển nó vào một hàm thuần túy khi cần, tôi không thấy tại sao điều này không nên ở trong thư viện chuẩn.
Oh, và như một phụ lục cho câu trả lời của tôi: Bạn có thể viết một phiên bản tổng quát hơn của 'randomInts' chỉ là' \ r -> fmap (randomRs r) getStdGen'. Điều này có kiểu '(Random a) => (a, a) -> IO [a]', nói cách khác, nó tạo ra một danh sách các giá trị ngẫu nhiên trong phạm vi đã cho cho bất kỳ loại nào là một thể hiện của 'Random'. –
Thậm chí tốt hơn, cảm ơn. – Steve
Tôi đoán đó là lý do tại sao chức năng 'randomList' của tôi thậm chí không cần phải nằm trong lib chuẩn nếu nó có thể ngắn, nhưng cậu bé không rõ ràng làm sao để viết nó cho một newb;) Vì vậy, tôi vẫn nghĩ rằng nó sẽ là vì lợi ích thuận tiện .. – Steve