我刚开始学习Haskell,在基本掌握了一些关于它的东西之后,我试着编写一个简单的函数来测试数n的素数,这就是我想出来的:
isPrime n i =
if n < 2
then 0
else if n == 2 || n == 3
then 1
else if (n `mod` i) == 0
then 0
else if i == floor(sqrt(n))
then 1
else isPrime n (i + 1)
算法本身似乎有用(我用另一种语言测试过),但是当试图为任何数字调用它时(即 isPrime 5 2 ),我得到以下错误:
<interactive>:9:1:
Could not deduce (Floating a10) arising from a use of `isPrime'
from the context (Num a)
bound by the inferred type of it :: Num a => a
at <interactive>:9:1-11
The type variable `a10' is ambiguous
Note: there are several potential instances:
instance Floating Double -- Defined in `GHC.Float'
instance Floating Float -- Defined in `GHC.Float'
In the expression: isPrime 5 2
In an equation for `it': it = isPrime 5 2
<interactive>:9:9:
Could not deduce (Num a10) arising from the literal `5'
from the context (Num a)
bound by the inferred type of it :: Num a => a
at <interactive>:9:1-11
The type variable `a10' is ambiguous
Note: there are several potential instances:
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
instance Num Integer -- Defined in `GHC.Num'
instance Num Double -- Defined in `GHC.Float'
...plus three others
In the first argument of `isPrime', namely `5'
In the expression: isPrime 5 2
In an equation for `it': it = isPrime 5 2
我试图指定类型,例如
isPrime :: Integer -> Integer -> Integer
但这只会返回一个不同的错误,甚至无法编译。
编辑:这是此版本的错误:
Prime.hs:10:48:
No instance for (RealFrac Integer) arising from a use of `floor'
In the second argument of `(==)', namely `floor (sqrt (n))'
In the expression: i == floor (sqrt (n))
In the expression:
if i == floor (sqrt (n)) then 1 else isPrime n (i + 1)
Prime.hs:10:54:
No instance for (Floating Integer) arising from a use of `sqrt'
In the first argument of `floor', namely `(sqrt (n))'
In the second argument of `(==)', namely `floor (sqrt (n))'
In the expression: i == floor (sqrt (n))
请帮助我,我该如何更改代码才能使其正常工作?提前谢谢。
答案 0 :(得分:3)
不平等
i < sqrt n
可以在不需要实数的情况下重写,并且无需整数平方根作为
进行计算i^2 < n
或
i*i < n
这足以让你的代码编译和工作。
isPrime n i =
if n < 2
then 0
else if n == 2 || n == 3
then 1
else if (n `mod` i) == 0
then 0
else if i*i < n
then isPrime n (i + 1)
else 1
main = print $ isPrime 13 2
您可能希望更改签名,以便更轻松地使用它。如果您将返回类型更改为Bool
并删除第二个参数,则可以编写if isPrime 13 then ...
或filter isPrime [1..30]
之类的内容。
isPrime :: Integral a => a -> Bool
isPrime n = go n 2
where
go n i =
if n < 2
then False
else if n == 2 || n == 3
then True
else if (n `mod` i) == 0
then False
else if i*i < n
then go n (i + 1)
else True
main = print $ filter isPrime [1..30]
这导致了解决方案,我们只检查通过sqrt n
的素数不会除n
。
primes :: [Integer]
primes = filter isPrime [1..]
isPrime :: Integer -> Bool
isPrime n = if n < 2
then False
else if n == 2 || n == 3
then True
else all (\i -> n `mod` i /= 0) . takeWhile (\i -> i*i <= n) $ primes
main = print $ take 10 primes
由于我们要多次计算i*i
,我们可以证明取而代之的是sqrt n
。 sqrt :: Floating a => a -> a
可以对任何Floating
个号码进行操作。我们可以使用fromIntegral :: (Integral a, Num b) => a -> b
将整数转换为任何其他数字类型。
primes :: [Integer]
primes = filter isPrime [1..]
isPrime :: Integer -> Bool
isPrime n = if n < 2
then False
else if n == 2 || n == 3
then True
else all (\i -> n `mod` i /= 0) . takeWhile (<= root_n) $ primes
where
root_n = floor . sqrt . fromIntegral $ n
main = print $ take 10 primes