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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With