我的练习是定义一个函数,该函数返回给定区间内至少三位数的素数列表。它必须与列表理解。
例如,在这种情况下,它必须返回 primeNumbers 100 200 = [101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181 , 191, 193, 197, 199].
这是我的代码
primesNumbers :: Int -> Int -> [Int]
primesNumbers a b = [n | n <- [a..b], n > 99, all (\x -> n `mod` x /= 0) [x | x <- [2.. max a b]]]
但是在这种情况下 primeNumbers 100 200,它只返回 [].
什么问题?
问题
首先,让我指出一个事实,即可能不需要
n > 99
。如果 a
大于 100,n
不能小于 99。要么你想要所有大于 99 的素数,要么你做错了。
所以我会在没有它的情况下工作。
如果我们分解你的代码,就有可能写成
primesNumbers :: Int -> Int -> [Int]
primesNumbers a b = [n | n <- [a..b], f a b n]
f :: Int -> Int -> Int -> Bool
f a b n = all (\x -> n `mod` x /= 0) [x | x <- [2.. max a b]]
如果我们想为
f
提供一个更好的名字,我们可以查看代码,发现它试图测试 2 和 max a b
之间的所有数字是否都是 n
的约数。所以让调用f
函数can_be_divided_by_a_number_between_a_and_b
.
所以你现在的功能是
primesNumbers a b = [n | n <- [a..b], can_be_divided_by_a_number_between_a_and_b a b n]
当你调用
primeNumbers 100 200
时,你想找到100到200之间的所有数字n
,不能被2到200之间的数字整除。现在,101是一个相关的选择吗?不,因为很明显 101 可以被 100 到 200 之间的数字整除……它可以被自己整除。
解决方案
现在你可以看到这不是你想要的。你的上限太高了。你想找到一种方法来表达它不能被严格地介于 1 和它本身之间的数字相除,即 Haskell 中的 ]1、n[ 或
[2 .. n-1]
。
让我们想办法写
cant_be_divided_by_a_number_stritly_between_2_and_itself
。为了简洁起见,我将其称为is_prime
,因为这是它的定义。
is_prime :: Int -> Bool
is_prime n = all (\x -> n `mod` x /= 0) [x | x <- [2 .. n-1]]
现在可以轻松编写函数了。因为你想要
a
和b
之间的所有质数,所以是
primeNumbers a b = [n | n <- [a..b], is_prime n]
结论
依我拙见,你应该从后者开始……写作
primeNumbers a b = [n | n <- [a..b], is_prime n]
是自上而下方法的开始,可帮助您将问题分解为更小的问题并逐步提供解决方案。 编写下一步
is_prime n
比尝试一步解决所有问题要容易得多。
你可以看到它可以很容易地推广到所有可能的谓词
p
with
verify_p_between_a_and_b p a b = = [n | n <- [a..b], p n]
所以
primesNumbers = verify_p_between_a_and_b is_prime
:)