Haskell“No instance for”错误 [英] Haskell "No instance for" error
问题描述
我试着写一个函数来检查一个数是否为素数。我写到:
primeCheck :: Int - > Int - > Bool
primeCheck n我
| n == 2 = True
| i == 1 = True
| n`mod` i == 0 = False
|否则= primeCheck n(i -1)
isPrime :: Int - > Bool
isPrime n = primeCheck n(floor(sqrt n))
错误:
没有使用
floor'$ b引起的(RealFrac Int)
primeCheck'的第二个参数中,即
的实例$ b可能的修正:为(RealFrac Int)添加实例声明
在(floor(sqrt n))'
isPrime'中:
在表达式中:primeCheck n(floor(sqrt n))
在等式
isPrime n = primeCheck n(floor(sqrt n))由于使用`sqrt'而导致(浮点型)没有实例
可能的修正:添加(Floating Int)的实例声明
在`floor'的第一个参数中,即`(sqrt n)'
在`primeCheck'的第二个参数中,即`(floor(sqrt n)) '
在表达式中:primeCheck n(floor(sqrt n))失败,模块加载:无。
当我将代码更改为希望解决此问题时:
primeCheck :: Int - > Int - > Bool
primeCheck n我
| n == 2 = True
| i == 1 = True
| n`mod` i == 0 = False
|否则= primeCheck n(i -1)
isPrime :: Int - > Bool
isPrime n = primeCheck n(floor(RealFrac(sqrt(Floating n))))
<
$ b
不在范围内:数据构造函数`RealFrac'
不在范围内:数据构造函数Floating'
我该如何解决这个问题?
浮动
是一个 typeclass ,不是构造函数或函数。你似乎已经发现你需要转换 n
类型。正确的方法是使用 fromIntegral
:
isPrime n = primeCheck n $ floor $ sqrt $(fromInteral n :: Double)
我们可以看到它的工作原理通过遵循函数的类型签名。
从 isPrime
的类型签名,我们看到 n
有类型 Int
。
因为 sqrt
需要一些浮动
类型(即a类型是类型类型的实例 Floating
),我们可以从 Int
转换为 Double
使用 fromIntegral
。请注意,来自整合的签名是
(积分a,数字b )=> a - > b
然后我们用 请注意,由于来自整数 Int
是 Integral
(所以输入类型可以)并且 Double 是
中看到错误 Num $ c的一个实例
的
sqrt
来获得一个新的 Double
。
floor
需要一个参数, RealFrac
。 Double 碰巧是
浮动
和 RealFrac的一个实例
,所以它会完成这项工作(不需要转换)。
floor
会将平方根转换回类型 Int
。
的输出类型是多态的,因此输入类型
/ sqrt
和 floor
,我们必须指定转换的类型为 Double
,否则编译器不会知道 Num 浮动
/ RealFrac
实例转换为。您可能会在... 歧义类型'a'。
您可以看到类型签名许多使用 Hoogle 的功能
EDIT
事实证明,来自整数的的显式类型签名是 not 需要。因此
isPrime n = primeCheck n $ floor $ sqrt $ fromInteral n
就够了。在我看来,只是提供明确的签名会更清楚,但在这种情况下不是必需的。你可以阅读更多关于它的信息这里。
I am trying to write a function that checks if a number is prime. I wrote this :
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))
And I get these errors :
No instance for (RealFrac Int) arising from a use of
floor' Possible fix: add an instance declaration for (RealFrac Int) In the second argument of
primeCheck', namely(floor (sqrt n))' In the expression: primeCheck n (floor (sqrt n)) In an equation for
isPrime': isPrime n = primeCheck n (floor (sqrt n))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.
When I change the code to this to hopefully fix the problem:
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))))
I get this :
Not in scope: data constructor `RealFrac'
Not in scope: data constructor `Floating'
How can I fix this?
Floating
is a typeclass, not a constructor or function. You do seem to have figured out that you need to convert the type of n
. The correct way to do this would be using fromIntegral
:
isPrime n = primeCheck n $ floor $ sqrt $ (fromIntegral n :: Double)
We can see why this works by following the type signatures of the functions.
From the type signature of isPrime
, we see n
has type Int
.
Since sqrt
expects some Floating
type (i.e. a type that is an instance of the typeclass Floating
), we can convert from an Int
to a Double
using fromIntegral
. Note that the signature of fromIntegral
is
(Integral a, Num b) => a -> b
Int
is an instance of Integral
(so the input type is okay) and Double
is an instance of Num
so the output type is okay.
Then we take the sqrt
to get a new Double
.
floor
expects an argument whose type is an instance of RealFrac
. Double
happens to be an instance of both Floating
and RealFrac
, so it will do the job (no conversion necessary).
floor
will convert the square root back to type Int
.
Note that since the output type of fromIntegral
is polymorphic, as is the input type of sqrt
and floor
, we have to specify the type of the conversion as Double
, otherwise the compiler won't know which Num
/Floating
/RealFrac
instance to convert to. You might see the error ambiguous type 'a' in ...
.
You can see the type signatures of many functions using Hoogle
EDIT
It turns out the explicit type signature for the fromIntegral
is not required. Thus
isPrime n = primeCheck n $ floor $ sqrt $ fromIntegral n
suffices. In my opinion, it would be clearer to just provide the explicit signature, but it is not necessary in this case. You can read more about it here.
这篇关于Haskell“No instance for”错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!