Say I want to write a function to decide whether a given integer number is prime, which type signature should I use?
isPrime :: Int -> Bool
or
isPrime :: (Integral a) => a -> Bool
What's the difference? Is there a particular reason to choose one over the other?
If so, in which situations should I use the two respectively?
From HaskellWiki. A type signature is a line like. inc :: Num a => a -> a. that tells, what is the type of a variable. In the example inc is the variable, Num a => is the context and a -> a is its type, namely a function type with the kind * -> * .
Since the type of elem y z is Bool , this matches with the function (&&) x , and thus the type of (&&) x (elem y z) is thus Bool .
a -> b Bool means... forall (a :: *) (b :: * -> *). a -> b Bool. b is therefore a type constructor taking a single type argument. Examples of single-argument type constructors abound: Maybe , [] , IO are all examples of things which you could use to instantiate b .
Haskell has two integral types, namely Int and Integer . Int is the type of limited-precision integers; this means that there is a smallest integer of type Int , namely minBound , and a greatest integer of type Int , namely maxBound .
The type Int -> Bool
means that your function operates on values of type Int
, which are size-limited integers (the maximum size being, I believe, machine-dependent).
The type (Integral a) => a -> Bool
means that your function operates on values of any type that has an instance of the Integral
type class--i.e., types that behave like integers in a particular way. The main reason to chose this over a concrete type is to create a more general-purpose function.
Generic forms using Integral
tend to be most useful when you need to work with integer-like types in other contexts--a good example being places where the standard library fails to do so, e.g. functions like replicate :: Int -> a -> [a]
. Code that operates on some specific integer-like type for its own purposes that wants to use that type with replicate
therefore needs to convert to Int
first, or import genericReplicate
from Data.List
.
What you might want to consider in your case is instead the type Integer
, which represents integers of arbitrary size. Since your main goal is the calculation, there's less value to supporting arbitrary integral types.
If memory serves me, the only instances of Integral
in the standard library are Int
and Integer
anyhow. (EDIT: As hammar reminds me in the comments, there are also instances for fixed-size types in Data.Int
and Data.Word
. There are also foreign types like CInt
but I was disregarding those intentionally.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With