奇怪的类型相关的错误

时间:2010-05-28 04:35:15

标签: haskell

我写了以下程序:

isPrime x = and [x `mod` i /= 0 | i <- [2 .. truncate (sqrt x)]]

primes = filter isPrime [1 .. ]

它应该构建素数列表。但我得到了这个错误:

[1 of 1] Compiling Main             ( 7/main.hs, interpreted )

7/main.hs:3:16:
    Ambiguous type variable `a' in the constraints:
      `Floating a' arising from a use of `isPrime' at 7/main.hs:3:16-22
      `RealFrac a' arising from a use of `isPrime' at 7/main.hs:3:16-22
      `Integral a' arising from a use of `isPrime' at 7/main.hs:3:16-22
    Possible cause: the monomorphism restriction applied to the following:
      primes :: [a] (bound at 7/main.hs:3:0)
    Probable fix: give these definition(s) an explicit type signature
                  or use -XNoMonomorphismRestriction
Failed, modules loaded: none.

如果我明确指定isPrime函数的签名:

isPrime :: Integer -> Bool
isPrime x = and [x `mod` i /= 0 | i <- [2 .. truncate (sqrt x)]]

我甚至无法编译isPrime函数:

[1 of 1] Compiling Main             ( 7/main.hs, interpreted )

7/main.hs:2:45:
    No instance for (RealFrac Integer)
      arising from a use of `truncate' at 7/main.hs:2:45-61
    Possible fix: add an instance declaration for (RealFrac Integer)
    In the expression: truncate (sqrt x)
    In the expression: [2 .. truncate (sqrt x)]
    In a stmt of a list comprehension: i <- [2 .. truncate (sqrt x)]

7/main.hs:2:55:
    No instance for (Floating Integer)
      arising from a use of `sqrt' at 7/main.hs:2:55-60
    Possible fix: add an instance declaration for (Floating Integer)
    In the first argument of `truncate', namely `(sqrt x)'
    In the expression: truncate (sqrt x)
    In the expression: [2 .. truncate (sqrt x)]
Failed, modules loaded: none.

你能帮助我理解,为什么我会收到这些错误?

2 个答案:

答案 0 :(得分:9)

你的问题在于电话sqrt x。为了了解原因,让我们检查一下GHCi中的isPrime的类型:

Prelude> let isPrime x = and [x `mod` i /= 0 | i <- [2 .. truncate (sqrt x)]]
Prelude> :t isPrime
isPrime :: (Integral a, Floating a, RealFrac a) => a -> Bool

这告诉我们isPrime的输入可以是任何类型,作为所有三个指定类型类的实例。换句话说,一个同时是整数和实数浮点数的数字。虽然原则上一个可以声明这样的类型,但它没有多大意义;事实上,确实没有这种类型。

现在这解释了你的两个错误。第一个错误是isPrime在没有类型签名的情况下过于多态。 monomorphism restriction(大致)说如果您通过模式匹配定义了一个值(例如f =Just x =,而不是g y =),则它不能是多态的类型类。因此,由于您没有为primes指定类型签名,因此它会推断类型primes :: (Integral a, RealFrac a, Floating a) => [a],然后抱怨,因为它是类型类多态。

第二个错误来自您施加的三个类型类约束的集合。 mod表示x必须属于Integral的实例类型; sqrt表示其输入必须是Floating的实例类型;并且truncate表示sqrt(与输入的类型相同)的结果必须具有RealFrac的实例类型。由于这些都用于完成相同的类型变量,x必须同时包含所有这些类型,而Integer既不是Floating也不是RealFrac的实例。因此,当您指定isPrime :: Integer -> Bool时,会出现错误,因为Integer需要是Floating的实例,但事实并非如此。要解决此问题,我们可以Hoogle搜索a conversion function of type (Integral a, Floating b) => a -> b。果然,Hoogle提出了更为笼统的fromIntegral :: (Integral a, Num b) => a -> b;在x的参数中sqrt之前插入该内容可以解决您的问题,因为您只会将x视为Integral的实例。这给了你:

-- The one other change I made: only positive numbers are prime, and 1 is not a
-- prime.
isPrime :: Integral i => i -> Bool
isPrime x | x <= 1    = False
          | otherwise = and [ x `mod` i /= 0
                              | i <- [2..truncate . sqrt $ fromIntegral x] ]

primes :: [Integer]
primes = filter isPrime [2..]

请注意,由于单态限制,您仍需要为primes提供类型签名!但无论如何,这可能是一个好主意。

答案 1 :(得分:4)

  

isPrime x =和[x mod i / = 0 | i&lt; - [2 .. truncate(sqrt(fromIntegral x))]]

您在sqrt的参数中错过了从Integral类型到Floating类型的转换。