[英]Haskell Does Not Evaluate Lazily takeWhile
isqrt :: Integer -> Integer
isqrt = floor . sqrt . fromIntegral
primes :: [Integer]
primes = sieve [2..] where
sieve (p:ps) = p : sieve [x | x <- ps, x `mod` p > 0]
primeFactors :: Integer -> [Integer]
primeFactors n = takeWhile (< n) [x | x <- primes, n `mod` x == 0]
這是我的代碼。 我想您猜到了我想做什么:使用無限質數列表的給定數質數的列表。 但是,這段代碼的評價並不懶惰。
當我使用ghci
和:l mycode.hs
並輸入primeFactors 24
,結果為[2, 3
(並且光標一直在那里閃爍),沒有其他Prelude>
提示。 我認為那里是一個問題。 我究竟做錯了什么?
謝謝。
takeWhile
永遠不會因復合參數而終止。 如果n
是復合的,則它沒有素數>= n
,因此takeWhile
只會坐在那里。
將takeWhile
應用於素數列表,然后使用n mod
x過濾結果,如下所示:
primeFactors n = [x | x <- takeWhile (<= n) primes, n `mod` x == 0]
(使用<=
代替<
以獲得最大的正確性,因此素數的素數將由該數組成)。
舉例說明發生了什么:
您的問題不是直接takeWhile
,而是列表理解。
[x | x <- primes, n `mod` x == 0]
對於n = 24
,我們得到24 `mod` 2 == 0
和24 `mod` 3 == 0
,因此此列表理解的值從2 : 3 : ...
。 但是請考慮...
部分。
列表理解必須保持從primes
提取值並檢查24 `mod` x == 0
。 由於不再有24
素數因子,因此沒有任何東西會通過該測試並作為列表理解的第三個值發出。 但是,由於總是有另一個質數要測試,因此它將永遠不會停止並得出結論,列表的其余尾部為空。
因為這是懶惰的評估,所以如果您只要求列出此列表的前兩個元素,那么您就可以了。 但是,如果你的程序需要有史以來第三個(甚至只是為了知道是否有第三個要素),那么列表解析會就冒永遠試圖想出一個。
takeWhile (< 24)
一直從其參數中拉出元素,直到找到非< 24
元素。 2
和3
都通過了該測試,因此takeWhile (< 24)
確實需要知道列表理解的第三個元素是什么。
但是takeWhile
並不是真正的問題; 問題是您寫了一個列表理解來查找所有主要因素(然后什么也沒有),然后嘗試對結果進行過濾以切斷對所有可能的更高質數的無限探索。可能是因素。 如果您停止考慮,那真的沒有任何意義。 根據定義,不是主要因子的任何事物都不能成為該列表的元素,因此您不能從該列表中濾除大於n
的非因子。 取而代之的是,您需要過濾對列表理解的輸入 ,以便它不會嘗試探索無限空間,如@nm的答案所示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.