【问题标题】:Writing an isPrime function in Haskell在 Haskell 中编写 isPrime 函数
【发布时间】:2020-04-07 19:53:27
【问题描述】:
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

我的问题是:

  • 这个功能有什么设计问题?

【问题讨论】:

  • ld 代表什么?这不是对数对数。所以:为你的函数使用正确的描述性名称。
  • 不,这不是一个特别有效的方法。有many better approaches

标签: haskell functional-programming primes primality-test


【解决方案1】:

太实用了。可以等价地表示为(*)

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

所以它在视觉上更明显,更清晰,one-liner 更容易处理。

试一试

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] 短很多,不是吗。它应该短得多 much,比这早 much 结束;甚至更短,里面有很多...

isPrime n = and [mod n p &gt; 0 | p &lt;- takeWhile (\p -&gt; p^2 &lt;= n) primes]
primes = 2 : filter isPrime [3..]

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


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

但是在这种形式下,它(可以说)是一个更清晰的代码,更直观。至少对我来说是这样。 :)

【讨论】:

  • 谢谢。你能解释一下这个比较[n] == take 1的目的是什么吗?
  • 我已将此添加到答案中。不客气。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多