我正在尝试编写一个函数来检查数字是否为素数.我写了这个:
primeCheck :: Int -> Int -> Bool
primeCheck n i
| n == 2 = True
| i == 1 = True
| n `mod` i == 0 = False
| otherwise = primeCheck n (i -1)
isPrime :: Int -> Bool
isPrime n = primeCheck n (floor (sqrt n))
Run Code Online (Sandbox Code Playgroud)
我收到这些错误:
使用
floor' Possible fix: add an instance declaration for (RealFrac Int) In the second argument ofprimeCheck'时没有(RealFrac Int)的实例,即isPrime(floor (sqrt n))' In the expression: primeCheck n (floor (sqrt n)) In an equation for':isPrime n = primeCheck n(floor(sqrt n))Run Code Online (Sandbox Code Playgroud)No instance for (Floating Int) arising from a use of `sqrt' Possible fix: add an instance declaration for (Floating Int) In the first argument of `floor', namely `(sqrt n)' In the second argument of `primeCheck', namely `(floor (sqrt n))' In the expression: primeCheck n (floor (sqrt n)) Failed, modules loaded: none.
当我将代码更改为此以希望解决问题时:
primeCheck :: Int -> Int -> Bool
primeCheck n i
| n == 2 = True
| i == 1 = True
| n `mod` i == 0 = False
| otherwise = primeCheck n (i -1)
isPrime :: Int -> Bool
isPrime n = primeCheck n (floor (RealFrac (sqrt (Floating n))))
Run Code Online (Sandbox Code Playgroud)
我明白了:
不在范围内:数据构造函数`RealFrac'
不在范围内:数据构造函数`Floating'
我怎样才能解决这个问题?
Floating是类型类,而不是构造函数或函数.你似乎已经发现你需要转换类型n.正确的方法是使用fromIntegral:
isPrime n = primeCheck n $ floor $ sqrt $ (fromIntegral n :: Double)
Run Code Online (Sandbox Code Playgroud)
我们可以通过遵循函数的类型签名来了解其原因.
从类型签名isPrime,我们看到n有类型Int.
由于sqrt需要某种Floating类型(即作为类型类的实例的类型Floating),我们可以从Inta 转换为Doubleusing fromIntegral.请注意,签名fromIntegral是
(Integral a, Num b) => a -> b
Run Code Online (Sandbox Code Playgroud)
Int是一个实例Integral(所以输入类型是可以的),并且Double是一个实例,Num所以输出类型是好的.
然后我们采取sqrt新的方式Double.
floor期望一个参数,其类型是一个实例RealFrac.Double恰好是两者的一个实例Floating 和 RealFrac,所以它会做的工作(无需转换).
floor将平方根转换回类型Int.
注意,由于输出型fromIntegral是多态的,因为是输入型sqrt和floor,我们必须指定转换为的类型Double,否则编译器将不知道哪个 Num/Floating/ RealFrac转换为实例.您可能会看到错误ambiguous type 'a' in ....
您可以使用Hoogle查看许多功能的类型签名
编辑
原来,为明确的类型签名fromIntegral是不是必需的.从而
isPrime n = primeCheck n $ floor $ sqrt $ fromIntegral n
Run Code Online (Sandbox Code Playgroud)
就足够了.在我看来,提供明确的签名会更清楚,但在这种情况下并不是必需的.你可以在这里阅读更多相关信息.