Lemma
Lemma

Reputation: 79

Ambiguous type variable error related to n ** 0.5

FINAL EDIT:

My final function is:

isPrime n = n > 1 && n < 4
    || n `mod` 2 /= 0
    && n `mod` 3 /= 0
    && length [x | x <- [5, 11..round (sqrt (fromIntegral n))], n `mod` x == 0 || n `mod` (x + 2) == 0] == 0

The issue was that I was trying to treat n as both a Floating in sqrt n, and as an Integral in n mod x. So I had to do fromIntegral n to force n to be treated as an Integral and not as a Floating.

Also I just screwed up some of my code.


So I have two functions:

primes = filterPrime [2..]
    where filterPrime (p:xs) = p : filterPrime [x | x <- xs, x `mod` p /= 0]

above is straight off of haskell.org, an example being take 5 primes results in [2,3,5,7,11]

My function isPrime is the following:

isPrime n = isPrime n = n > 1 && n < 4
    || (n `mod` 2 == 0 || n `mod` 3 == 0)
    && length [x | x <- [5, 11..round (n ** 0.5)], n `mod` x == 0 || n `mod` (x + 2) == 0] == 0

However, when I call isPrime I get the error:

EulerMath.hs:6:33: error:
    * No instance for (RealFrac Int) arising from a use of `round'
    * In the expression: round (n ** 0.5)
      In the expression: [5, 11 .. round (n ** 0.5)]
      In a stmt of a list comprehension: x <- [5, 11 .. round (n ** 0.5)]
  |
6 |     && length [x | x <- [5, 11..round (n ** 0.5)], n `mod` x == 0 || n `mod` (x + 2) == 0] == 0
  |                                 ^^^^^^^^^^^^^^^^

EulerMath.hs:6:40: error:
    * No instance for (Floating Int) arising from a use of `**'
    * In the first argument of `round', namely `(n ** 0.5)'
      In the expression: round (n ** 0.5)
      In the expression: [5, 11 .. round (n ** 0.5)]
  |
6 |     && length [x | x <- [5, 11..round (n ** 0.5)], n `mod` x == 0 || n `mod` (x + 2) == 0] == 0
  |                                        ^^^^^^^^

EulerMath.hs:6:45: error:
    * No instance for (Fractional Int) arising from the literal `0.5'
    * In the second argument of `(**)', namely `0.5'
      In the first argument of `round', namely `(n ** 0.5)'
      In the expression: round (n ** 0.5)
  |
6 |     && length [x | x <- [5, 11..round (n ** 0.5)], n `mod` x == 0 || n `mod` (x + 2) == 0] == 0
  |                                             ^^^

I don't know how to annotate the isPrime function correctly (read: I don't know how to annotate properly at all) so I don't get this error

Upvotes: 1

Views: 200

Answers (2)

Yuri Kovalenko
Yuri Kovalenko

Reputation: 1375

The problem is, n ** 0.5 (or simply written as sqrt n) requires n to be Floating:

(**) :: Floating a => a -> a -> a
sqrt :: Floating a => a -> a

But mod requires n to be Integral:

mod :: Integral a => a -> a -> a

Haskell is a language, where there is no implicit type conversions, so you can't just pass an Int to sqrt. You can try it in GHCi:

x = 4 :: Int
sqrt x -- error

To solve that conflict you can use such a function fromIntegral :: (Integral a, Num b) => a -> b that allows you to convert any Integral type to any Num type, and all Floating types are Num, so you will be able to use n in sqrt:

isPrime n = length [x | x <- take (round (sqrt (fromIntegral n))) primes, n `mod` x == 0] == 0

Also, we can simplify it a bit with $ application operator to omit some () and null function to check whether the list is empty:

isPrime n = null [x | x <- take (round $ sqrt $ fromIntegral n) primes, n `mod` x == 0]

Try it there: https://repl.it/@Yuri12358/so-primes

Upvotes: 1

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

Let's look at the types of tge involved operators.

(**) :: Floating a => a -> a -> a
mod :: Integral a => a -> a -> a

You apply both operators to the same variable n. There is no type that satisfies both constraints however, and even if there where, Haskell wouldn't know how to choose one.

There are a couple of ways to solve this. One is to say fromIntegral n ** 0.5 (or, perhaps better, use sqrt). Another one can be found here.

Last but not least you may want to notice that taking √n elements from a list of primes doesn't quite make sense. You want primes that are less than √n. Look at the takeWhile function.

Upvotes: 1

Related Questions