素数问题
【题目】 2,3,5,7,11 … 是前几个素数,求 1000 以内一共有多少个素数。
最容易想到的解法,当然是先造一个函数,能判断一个数是不是素数。
从2开始的小于 n的数字,如果能除尽 n,则n不是素数。
is_su :: Int -> Bool
is_su n = [ 1 | x <- [2..(n-1)], n `mod` x == 0 ] == []
su_shu = filter is_su [2..]
r = length $ takeWhile (<1000) su_shu
main = print r
haskell 的这种实现在简洁的同时,保持了很高的弹性。
将来题目的形式上的变化,很容易应对。这是纯函数思维一个附带的好处。
注意,[2…] 是一个无限的序列,因而su_shu 也是一个无限序列(这里受到了Int 签名的限制)
惰性的好处也显现出来。is_su 不会对所有可能的数去试除。因为它的惰性,只要有一个数字除开了, == [] 就不成立了,因而试除的工作也就不会继续下去了。
这种一旦出现 xxx情况就中止
的模式也可以用 any 或 all 来更明确地表达出来:
is_su n = all (\x -> n `mod` x /= 0) [2..(n-1)]
这个表达式,简直就是素数的定义本身,你看,它读作:
素数就是:从2开始的,所有比它小的整数,都除不开它。
这种求素数的办法效率不高。有一种筛法
目前仍然是比较高效的方式。
其思想是从2开始,把所有2的倍数全删掉。然后剩下的数字从3开始,再删去3的倍数…
最后剩下的就是素数了。
haskell 主页上引以傲的一段代码,正是用此法产生了一个无限的素数序列。
su_shu = f [2..] where
f (p:xs) = p : f [x | x <- xs, x `mod` p /= 0]
num = length $ takeWhile (<1000) su_shu
main = print num
这段代码以如此简练的逻辑实现了一个无限的素数列,多少让人惊讶!当然,实际上求很大的素数时效率仍有问题。但你用 c 写个程序,来第10000个素数试试,就知道haskell的优美了。
现在,在 haskell 中,你只需要写: su_shu !! 10000
当然,如果你是笔记本上运行,要耐心等一会儿的。考虑到敲的这么几个码,你就知足吧!