How would you define the following type signatures in plain english:
Ord a => ...
Eq a => ...
Num a => ...
Could you describe the meaning of these and let me know what the differences are (in terms of how I would explain it to someone else)?
Thanks.
These are all examples of "class constraints": they constrain what types can be used in place of the type variable which follows them (a
in this case), requiring that it belong to a particular type class. Ord
, Eq
and Num
are examples of type classes.
Ord a => ...
means a
is a type which has a natural notion of order associated with it. For example, integers can be naturally arranged from smaller to larger. In mathematical terms, there exists a total order on a
. An obvious example a function which requires this constraint is sort :: Ord a => [a] -> [a]
; read this signature as saying that sort
only works on lists of things which can be put in order relative to one another.
Eq a => ...
means a
is a type whose members can be compared to each other for some notion of equality. In mathematical terms, there exists an equivalence relation on a
. Note that this is a superclass of Ord
, meaning anything that has a notion of ordering must also have a notion of equivalence. An example of a function which requires this constraint is elem :: Eq a => a -> [a] -> Bool
(which determines if a list contains a given element); read this signature as saying that elem
only works on lists of things which can be compared to one another for equality. If you think about how you would write elem
yourself, that should make sense.
Num a => ...
means a
is a numeric type, meaning it supports some basic arithmetical operations: +
, *
, -
, abs
. I believe this is roughly similar to the mathematical notion of a ring. Basically all the types you think of as "number types" belong to this class: Int
, Double
, etc. You would see the Num a =>
constraint in front of a signature if the function was written to work generically with any kind of number. For example, sum :: Num a => [a] -> a
, which sums all the elements of a list of numbers, can work equally well on [Int]
, [Double]
, [Rational]
, etc... all it has to do is add up its contents, no matter what kind of numbers they are. But numbers they must be!
Basically, these type classes/constraints are an approach to "principled overloading" of functions. We can use (==) :: Eq a => a -> a -> Bool
on various types, but not just any types. Some things, for example functions, don't make sense to compare for equality (perhaps because equality isn't decidable for that type), and it never makes sense to compare two things of different types for equality (contrast this with Java, where you can compare any two objects of possibly different types for equality).
For further (very accessible) reading on type classes and constraints, I highly recommend Learn You a Haskell.
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