简体   繁体   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]

Here is my code. 这是我的代码。 I think you guessed what I am trying to do: A list of prime factors of a given number using infinite list of prime numbers. 我想您猜到了我想做什么:使用无限质数列表的给定数质数的列表。 But this code does not evaluate lazily. 但是,这段代码的评价并不懒惰。

When I use ghci and :l mycode.hs and enter primeFactors 24 , the result is [2, 3 ( and the cursor constantly flashing there) there isn't a further Prelude> prompt. 当我使用ghci:l mycode.hs并输入primeFactors 24 ,结果为[2, 3 (并且光标一直在那里闪烁),没有其他Prelude>提示。 I think there is a problem there. 我认为那里是一个问题。 What am I doing wrong? 我究竟做错了什么?

Thanks. 谢谢。

takeWhile never terminates for composite arguments. takeWhile永远不会因复合参数而终止。 If n is composite, it has no prime factors >= n , so takeWhile will just sit there. 如果n是复合的,则它没有素数>= n ,因此takeWhile只会坐在那里。

Apply takeWhile to the primes list and then filter the result with n mod x, like this: takeWhile应用于素数列表,然后使用n mod x过滤结果,如下所示:

primeFactors n = [x | x <- takeWhile (<= n) primes, n `mod` x == 0]

( <= is used instead of < for maximum correctness, so that prime factors of a prime number would consist of that number). (使用<=代替<以获得最大的正确性,因此素数的素数将由该数组成)。

Have an illustration of what happens: 举例说明发生了什么:

http://sketchtoy.com/67338195 http://sketchtoy.com/67338195

Your problem isn't directly takeWhile , but rather the list comprehension. 您的问题不是直接takeWhile ,而是列表理解。

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

For n = 24 , we get 24 `mod` 2 == 0 and 24 `mod` 3 == 0 , so the value of this list comprehension starts with 2 : 3 : ... . 对于n = 24 ,我们得到24 `mod` 2 == 024 `mod` 3 == 0 ,因此此列表理解的值从2 : 3 : ... But consider the ... part. 但是请考虑...部分。

The list comprehension has to keep pulling values from primes and checking 24 `mod` x == 0 . 列表理解必须保持从primes提取值并检查24 `mod` x == 0 Since there are no more prime factors of 24 nothing will ever pass that test and get emitted as the third value of the list comprehension. 由于不再有24素数因子,因此没有任何东西会通过该测试并作为列表理解的第三个值发出。 But since there's always another prime to test, it will never stop and conclude that the remaining tail of the list is empty. 但是,由于总是有另一个质数要测试,因此它将永远不会停止并得出结论,列表的其余尾部为空。

Because this is lazily evaluated, if you only ever ask for the first two elements of this list then you're fine. 因为这是懒惰的评估,所以如果您只要求列出此列表的前两个元素,那么您就可以了。 But if your program ever needs the third one (or even just to know whether or not there is a third element), then the list comprehension will just spin forever trying to come up with one. 但是,如果你的程序需要有史以来第三个(甚至只是为了知道是否第三个要素),那么列表解析会就冒永远试图想出一个。

takeWhile (< 24) keeps pulling elements from its argument until it finds one that is not < 24 . takeWhile (< 24)一直从其参数中拉出元素,直到找到非< 24元素。 2 and 3 both pass that test, so takeWhile (< 24) does need to know what the third element of the list comprehension is. 23都通过了该测试,因此takeWhile (< 24) 确实需要知道列表理解的第三个元素是什么。

But it's not really a problem with takeWhile ; 但是takeWhile并不是真正的问题; the problem is that you've written a list comprehension to find all of the prime factors (and nothing else), and then trying to use a filter on the results of that to cut off the infinite exploration of all the higher primes that can't possibly be factors. 问题是您写了一个列表理解来查找所有主要因素(然后什么也没有),然后尝试对结果进行过滤以切断对所有可能的更高质数的无限探索。可能是因素。 That doesn't really make sense if you stop to think about it; 如果您停止考虑,那真的没有任何意义。 by definition anything that isn't a prime factor can't be an element of that list, so you can't filter out the non-factors larger than n from that list. 根据定义,不是主要因子的任何事物都不能成为该列表的元素,因此您不能从该列表中滤除大于n的非因子。 Instead you need to filter the input to that list comprehension so that it doesn't try to explore an infinite space, as @nm's answer shows. 取而代之的是,您需要过滤对列表理解的输入 ,以便它不会尝试探索无限空间,如@nm的答案所示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM