所以我设计了以下函数来查看给定数字是否是 Haskell 中的素数(它假设第一个素数是 2):
isPrime k = length [ x | x <- [2..k], k `mod` x == 0] == 1
即使它可以被几个数字整除,它也有继续评估的明显缺陷:(。当它使用列表推导找到多个解决方案时,是否有任何理智的方法可以“削减”评估?
另外,您会尝试哪些其他实现?我不是在这里寻找性能,我只是想看看是否还有其他更“haskellish”的方式来做同样的事情。
所以我设计了以下函数来查看给定数字是否是 Haskell 中的素数(它假设第一个素数是 2):
isPrime k = length [ x | x <- [2..k], k `mod` x == 0] == 1
即使它可以被几个数字整除,它也有继续评估的明显缺陷:(。当它使用列表推导找到多个解决方案时,是否有任何理智的方法可以“削减”评估?
另外,您会尝试哪些其他实现?我不是在这里寻找性能,我只是想看看是否还有其他更“haskellish”的方式来做同样的事情。
对您的代码的快速更改将“短路”评估,并依赖于 Haskell 列表的惰性,是:
isPrime k = if k > 1 then null [ x | x <- [2..k - 1], k `mod` x == 0] else False
的第一个除数k
将导致列表非空,而 Haskell 的实现null
将只查看列表的第一个元素。
但是,您应该只需要检查sqrt(k)
:
isPrime k = if k > 1 then null [ x | x <- [2..isqrt k], k `mod` x == 0] else False
当然,如果您希望进行高性能素性测试,则首选库。
这是haskell.org中haskell中素数的最佳资源
这里是prime.hs github项目
这可能不是直接相关的,但是关于在函数式语言中寻找素数的话题,我发现 Melissa E. O'Neill 的The Genuine Sieve of Eratosthenes非常有趣。
我喜欢这种方法:
首先制作函数以获取 n 的所有因数:
factors n = [x | x <- [1..n], mod n x == 0]
然后检查因子是否只是给定的数字和 1,如果是,则该数字是素数:
prime n = factors n == [1,n]
忽略素数问题,并专注于更有效方法的窄点length xs == n
:
hasLength :: Integral count => [a] -> count -> Bool
_ `hasLength` n | n < 0 = False
[] `hasLength` n = n == 0
(_ : xs) `hasLength` n = xs `hasLength` (pred n)
isPrime k = [ x | x <- [2..k], k `mod` x == 0)] `hasLength` 1
这可能是愚蠢和低效的(我是一个完整的 Haskell 新手),但函数 isMyNumberPrime (在 ghci 中)似乎告诉你一个数字是否是素数。
factors n = [x | x <- [2..(n`div` 2)], mod n x == 0]
factormap n = fmap factors $ factors n
isMyNumberPrime n = case factormap n of [] -> True; _ -> False