簡體   English   中英

Haskell不會懶惰地評估

[英]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]

(使用<=代替<以獲得最大的正確性,因此素數的素數將由該數組成)。

舉例說明發生了什么:

http://sketchtoy.com/67338195

您的問題不是直接takeWhile ,而是列表理解。

[x | x <- primes, n `mod` x == 0]

對於n = 24 ,我們得到24 `mod` 2 == 024 `mod` 3 == 0 ,因此此列表理解的值從2 : 3 : ... 但是請考慮...部分。

列表理解必須保持從primes提取值並檢查24 `mod` x == 0 由於不再有24素數因子,因此沒有任何東西會通過該測試並作為列表理解的第三個值發出。 但是,由於總是有另一個質數要測試,因此它將永遠不會停止並得出結論,列表的其余尾部為空。

因為這是懶惰的評估,所以如果您只要求列出此列表的前兩個元素,那么您就可以了。 但是,如果你的程序需要有史以來第三個(甚至只是為了知道是否第三個要素),那么列表解析會就冒永遠試圖想出一個。

takeWhile (< 24)一直從其參數中拉出元素,直到找到非< 24元素。 23都通過了該測試,因此takeWhile (< 24) 確實需要知道列表理解的第三個元素是什么。

但是takeWhile並不是真正的問題; 問題是您寫了一個列表理解來查找所有主要因素(然后什么也沒有),然后嘗試對結果進行過濾以切斷對所有可能的更高質數的無限探索。可能是因素。 如果您停止考慮,那真的沒有任何意義。 根據定義,不是主要因子的任何事物都不能成為該列表的元素,因此您不能從該列表中濾除大於n的非因子。 取而代之的是,您需要過濾對列表理解的輸入 ,以便它不會嘗試探索無限空間,如@nm的答案所示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM