开发者

Learning Haskell, care to help out with coding style?

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))


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.


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])
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜