1
\$\begingroup\$

I am starting to learn Haskell, so I coded a naive solution to the primality test and summation of primes (Project Euler Problem 10: sum of all primes under 2 million) . As I have an imperative programming background, can you tell me if my code is functional enough?

isqrt :: Int -> Int 
isqrt n = floor(sqrt(fromIntegral n))
factors n = filter (\i -> n `mod` i == 0) [1..(isqrt(n))]
is_prime n = (factors n) == [1]
main = print (sum (filter is_prime [2..2000000]))
asked Feb 11, 2015 at 13:22
\$\endgroup\$
2
  • \$\begingroup\$ Not an haskell expert (to say the least) but when you know you will perform a high number of prime checks and you know an upper bound for the number you'll check, it is much more efficient to implement some kind of Sieve of Eratosthenes. \$\endgroup\$ Commented Feb 11, 2015 at 17:29
  • \$\begingroup\$ I know but I just wanted ro implement a very easy algoritmh \$\endgroup\$ Commented Feb 11, 2015 at 19:08

1 Answer 1

3
\$\begingroup\$

You have some of the right idea, but it looks like you're writing in Lisp. ;-)

There's no need to surround a single parameter in parentheses to pass it to a function, you mostly get this right so I think this one instance was just a slip up.

factors n = filter (\i -> n `mod` i == 0) [1..(isqrt(n))]
-- ^ ^

Function application has the highest precedence of any operator in Haskell, so these parentheses are unnecessary.

factors n = filter (\i -> n `mod` i == 0) [1..(isqrt n)]
-- ^ ^
is_prime n = (factors n) == [1]
-- ^ ^

Common Haskell style often prefers function composition to function application.

isqrt n = floor . sqrt . fromIntegral $ n

Are you familiar with function composition from mathematics? It's the same thing here, f . g $ x is equivalent to f (g x), but it puts the emphasis of the code on the composition of functions and not the manipulation of values. This is a different mindset from what you're going to be used to coming from an imperative language, but it is integral to developing the Haskell "house style" and really effectively leveraging combinators and function composition.

Haskellers also love writing functions pointfree. This means leaving off the arguments that are being passed to your function where possible. Check out the Haskell Wiki on pointfree style for some motivation and examples.

isqrt = floor . sqrt . fromIntegral

All top-level definitions should be annotated with a type signature in Haskell. There are myriad reasons for always doing this, including acting as documentation, providing necessary information to the compiler on occasions, serving as a check against your own understanding of what your function is doing, &c.

factors :: Int -> [Int]
is_prime :: Int -> Bool
main :: IO ()

Common Haskell style is to use camelCase instead of snake_case, so isPrime instead of is_prime.

Wherever possible, Haskellers usually prefer case analysis to equality testing. If you rewrite factors to exclude testing 1 (which is a tautological case anyway, why bother evaluating it?) you can check if the list returned by factors is null with null, which enables more function composition goodness.

factors :: Int -> [Int]
factors n = filter (\i -> n `mod` i == 0) [2..isqrt n]
isPrime :: Int -> Bool
isPrime = null . factors

Here's the whole thing with my style adjustments.

isqrt :: Int -> Int 
isqrt = floor . sqrt . fromIntegral
factors :: Int -> [Int]
factors n = filter (\i -> n `mod` i == 0) [2..isqrt n]
isPrime :: Int -> Bool
isPrime = null . factors
main :: IO ()
main = print . sum . filter isPrime $ [2..2000000]

Line breaks are important too. Doesn't it look much less cramped?


A comprehensively correct version of isPrime using guards to defend the honor of the negative numbers.

isPrime :: Int -> Bool
isPrime n | n < 2 = False
 | otherwise = null . factors $ n
answered Feb 11, 2015 at 21:21
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.