在Haskell中编写isPrime函数

时间:2019-12-14 18:54:56

标签: haskell functional-programming primes primality-test

isPrime :: Int -> Bool
isPrime n = leastDivisor n == n

leastDivisor :: Int -> Int 
leastDivisor n = leastDivisorFrom 2 n

leastDivisorFrom :: Int -> Int -> Int
leastDivisorFrom k n | n `mod` k == 0 = k
                     | otherwise      = leastDivisorFrom (k + 1) n

我的问题是:

  • 此功能有哪些设计问题?

1 个答案:

答案 0 :(得分:2)

它太可操作了。可以等效地表示为(*)

['google.com']

因此,它在视觉上更明显,更清晰,one-liner更易于处理。

尝试为

isPrime :: Integer -> Bool
isPrime n  =  [n] == take 1 [i | i <- [2..n], mod n i == 0]

显示它有多慢。我们可以尝试将其重写为

GHCi> zipWith (-) =<< tail $ filter isPrime [2..]
[1,2,2,4,2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,
4,2,4,6,2,10,6,6,6,2,6,4,2,10,14,4,2,4,14,6,10,2,4,6,8,6,6,4,6,8,4,8,10,2,10,2,6,4,6,8,4,2,4,12,8,4,
8,4,6,12,2,18,6,10,6,6,2,6,10,6,6,2,6,6,4,2,12,10,2,4,6,6,2,12,4,6,8,10,8,10,8,6,6,4,8,6,4,8,4,14,10
......

但是isPrime n = null [i | i <- [2..n-1], mod n i == 0] = none (\ i -> mod n i==0) [2..n-1] = all (\ i -> mod n i > 0) [2..n-1] = and [mod n i > 0 | i <- [2..n-1]] 不是 [2..n-1]短很多,不是吗?它应该短很多很多,比这早结束很多;甚至更短,里面有很多 ...

  

[2..n]
 isPrime n = and [mod n p > 0 | p <- takeWhile (\p -> p^2 <= n) primes]

此后的下一个改进就是getting rid of mod


(*)表示与您的primes = 2 : filter isPrime [3..]完全相同的计算操作。 leastDivisor n == n仅将数字的第一个除数用作列表;它的长度必须为1;然后将其与单元素列表take 1进行比较,就相当于将第一个(即最小的)除数与数字[n]进行比较。正是您的代码在做什么。

但是以这种形式,它(可以说)是一个更清晰的代码,在视觉上更明显。至少对我来说是如此。 :)