Search code examples
haskellambiguous

haskell list of primes construction; ambiguos type variable


I'm trying to make function primes which is a list of prime numbers, but somehow I have failed. The compiler throws an error I don't know how to resolve:

Error:

Ambiguous type variable 'a0'

Code:

candidates :: [Integer]
candidates = [2]++[3,5..]

primes :: [Integer]
primes = filter is_prime candidates

is_prime :: Integer -> Bool
is_prime candidate
    | candidate == 1 = False
    | candidate == 2 = True
    | candidate == 3 = True
    | otherwise = r_is_prime candidate 0

-- r as recursive
r_is_prime :: Integer -> Integer -> Bool
r_is_prime candidate order
    | n_th_prime >= max_compared_prime = True
    | candidate `mod` n_th_prime  == 0 = False
    | otherwise = if (r_is_prime candidate (order+1) ) then True else False
    where 
        n_th_prime = candidates !! fromIntegral(order)
        -- this is the line that throws an error...
        max_compared_prime = fromIntegral ( ceiling ( fromIntegral ( sqrt ( fromIntegral candidate))))

Solution

  • In

    max_compared_prime = fromIntegral ( ceiling ( fromIntegral ( sqrt ( fromIntegral candidate))))
    

    you have a fromIntegral too much. sqrt has type

    sqrt :: Floating a => a -> a
    

    so the result of sqrt is not a member of an Integral type. And the result of ceiling is an Integral type, so the last fromIntegral is superfluous (but does not harm).

    max_compared_prime = ceiling ( sqrt ( fromIntegral candidate))
    

    is all you need in that line.

    Note, however, that

    n_th_prime = candidates !! fromIntegral(order)
    

    means that to test against the n-th candidate prime, the list of candidates has to be traversed until the n-th prime has been reached. Thus testing against the n-th candidate is O(n) here instead of O(1) [Well, assuming that numbers are bounded] which a single division is.

    A more efficient trial division only tries primes for the division and remembers where in the list of primes it was when it goes on to the next prime. For example

    is_prime :: Integer -> Bool
    is_prime n
        | n < 2     = False
        | n < 4     = True
        | otherwise = trialDivision primes
          where
            r = floor (sqrt $ fromIntegral n)
            trialDivision (p:ps)
                | r < p     = True
                | otherwise = n `rem` p /= 0 && trialDivision ps
    

    Just traverses the list of primes in order to do the trial division, hence going from one prime to the next is a simple step in the list.