在我自己的Haskell函数中输入错误

时间:2015-09-03 14:59:47

标签: haskell

我刚开始学习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))

请帮助我,我该如何更改代码才能使其正常工作?提前谢谢。

1 个答案:

答案 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 nsqrt :: 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