Haskell: Difference between "(Int a, Bool b) => a -> b" and Int -> Bool [duplicate]
Solution 1:
You are misreading the tutorial. It would say the type signature should be
is_prime :: (Integral a) => a -> Bool
-- NOT Integer a
These are different types:
-
Integer -> Bool
- This is a function that takes a value of type
Integer
and gives back a value of typeBool
.
- This is a function that takes a value of type
-
Integral a => a -> Bool
- This is a function that takes a value of type
a
and gives back a value of typeBool
. - What is
a
? It can be any type of the caller's choice that implements theIntegral
type class, such asInteger
orInt
.
- This is a function that takes a value of type
(And the difference between Int
and Integer
? The latter can represent an integer of any magnitude, the former wraps around eventually, similar to int
s in C/Java/etc.)
The idiomatic way to loop depends on what your loop does: it will either be a map, a fold, or a filter.
Your loop in main
is a map, and because you're doing i/o in your loop, you need to use mapM_
.
let dump i = putStrLn ( show (i) ++ " is a prime? " ++ show (is_prime i) )
in mapM_ dump [1..n]
Meanwhile, your loop in is_prime
is a fold (specifically all
in this case):
is_prime :: Integer -> Bool
is_prime n = all nondivisor [2 .. n `div` 2]
where
nondivisor :: Integer -> Bool
nondivisor i = mod n i > 0
(And on a minor point of style, it's conventional in Haskell to use names like isPrime
instead of names like is_prime
.)
Solution 2:
Part 1: If you look at the tutorial again, you'll notice that it actually gives type signatures in the following forms:
isPrime :: Integer -> Bool
-- or
isPrime :: Integral a => a -> Bool
isPrime :: (Integral a) => a -> Bool -- equivalent
Here, Integer
is the name of a concrete type (has an actual representation) and Integral
is the name of a class of types. The Integer
type is a member of the Integral
class.
The constraint Integral a
means that whatever type a
happens to be, a
has to be a member of the Integral
class.
Part 2: There are plenty of ways to write such a function. Your recursive definition looks fine (although you might want to use n < i * i
instead of n < 2 * i
, since it's faster).
If you're learning Haskell, you'll probably want to try writing it using higher-order functions or list comprehensions. Something like:
module Main (main) where
import Control.Monad (forM_)
isPrime :: Integer -> Bool
isPrime n = all (\i -> (n `rem` i) /= 0) $ takeWhile (\i -> i^2 <= n) [2..]
main :: IO ()
main = do n <- readLn
forM_ [1..n] $ \i ->
putStrLn (show (i) ++ " is a prime? " ++ show (isPrime i))