tags:

views:

197

answers:

2

I started learning haskell yesterday and I got stuck on a problem. After a bit of trying different things I thought I'd finally come here and ask how to fix this. Also, feel free to criticize the way I have done things so far so I can know what direction to go. Thanks.

module Main where
main = putStrLn lastPrime
    where
        lastPrime :: String
        lastPrime = show(last(take 10001 primes))
        primes :: [Int]
        primes = [x| x <- [1..],length [a| a <- [1..lessen(x)], mod x a /= 0] == x - 2]
        lessen :: Int -> Int
        lessen a = ceiling(sqrt(a))
+5  A: 

To fix your type error, you want this:

    lessen :: Int -> Int
    lessen a = ceiling (sqrt (fromIntegral a))

a has type Int, but sqrt is expecting a floating point type, and the easiest way to convert an integral type to another numeric type is fromIntegral.

Simon Marlow
Awesome, that fixed it. Thanks!
BiscottiLighter
I am a bit new to Haskell but... I thought type inference meant that it was not necessary to precise the types of `lastPrime`, `primes`, `lessen`.
Matthieu M.
+3  A: 

In addition to the type error in lessen you have a logic error in primes:

length [a| a <- [1..lessen(x)], mod x a /= 0] == x - 2

You're (rightly) only considering elements up to lessen x. This has the consequence that the list will almost never have exactly x - 2 elements. As a consequence you'll get into an infinite loop when trying to get more than two elements out of that list (because there is no 3rd element for which the condition is true, but haskell doesn't know that so it iterates to infinity trying to find it).

Also note that taking the length of a list is an O(n) operation and there's almost always a better way to achieve what you want.

As a style note, I would recommend defining a separate method isPrime. This will make your code look like this:

module Main where
main = putStrLn lastPrime
    where
        lastPrime :: String
        lastPrime = show(last(take 10001 primes))
        isPrime x = length [a| a <- [1..lessen(x)], mod x a /= 0] == x - 2]
        primes :: [Int]
        primes = [x| x <- [1..], isPrime x]
        lessen :: Int -> Int
        lessen a = ceiling(sqrt (fromIntegral a))

This IMHO makes the list comprehension much more readable. However it still contains the bug. To get rid of the bug, I'd suggest defining isPrime using a different approach. Going up to lessen x is fine (except you should start from 2 because 1 cleanly divides everything), but instead of building a new list with all the divisors, you should just check whether any of the numbers in the range divides x. For this we can use the higher order function any, so we get this:

isPrime x = not (any (\a -> mod x a == 0) [2 .. lessen x])
sepp2k
Thanks, I'm new to haskell and wrapping my head around functional programming is a little tough.
BiscottiLighter
What was this downvoted for?
sepp2k