我写了以下程序:
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.
你能帮助我理解,为什么我会收到这些错误?
答案 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类型的转换。