6
votes

This is an example in Learn You A Haskell, chapter on higher order functions:

compareWithHundred :: (Num a, Ord a) => a -> Ordering  
compareWithHundred x = compare 100 x  

While the idea of the function is clear for me, I'm not sure why type signature is (Num a, Ord a). We only pass integer that is to be compared to the function, of type Int. What Ord stands for here, and why is implicitly passed argument in type signature?

2

2 Answers

12
votes

That's not the only possible signature for this signature. It happens to be the most general one. compareWithHundred :: Int -> Ordering is actually a possible instantiation – the polymorphic a argument can be instatiated with any orderable number type, which does sure enough include Int, but also Integer, Rational, Double...

Prelude> let compareWithHundred :: (Num a, Ord a) => a -> Ordering; compareWithHundred x = compare 100 x
Prelude> compareWithHundred (99 :: Int)
GT
Prelude> compareWithHundred (100.3 :: Double)
LT

Not all number types permit you to order-compare them though – the classical example where this is not possible are complex numbers (which have “more than one direction” in which you could order them).

Prelude Data.Complex> compareWithHundred (100 :+ 30 :: Complex Double)

<interactive>:10:1:
    No instance for (Ord (Complex Double))
      arising from a use of ‘compareWithHundred’
    In the expression: compareWithHundred (100 :+ 30 :: Complex Double)
    In an equation for ‘it’:
        it = compareWithHundred (100 :+ 30 :: Complex Double)

Hence you need to require both that the argument is a number (so there exists a value 100 which to compare with) and that the argument is in the Ord class. This combined constrained is written (Num a, Ord a).

8
votes

I have something to add, in case you couldn't gather something from leftaroundabout's thorough answer.

Everything to the left of => in a type signature is a constraint. Read the type like this:

compareWithHundred :: (Num a, Ord a) => a -> Ordering
                      ^^^^^^^^^^^^^^    ^    ^^^^^^^^
                       constraints      |         |
                                 argument type    |
                                             result type

So you only pass one argument to the function because there is only one argument in the type signature, a. a is a type variable, and can be replaced with any type as long as that type satisfies the constraints.

The Num a says that whatever you replace a with has to be numeric (so it can be Int, Integer, Double, ...), and the Ord a says that it has to be comparable. leftroundabout's answer goes into more detail about why you need both, I just wanted to make sure you knew how to read the signature.

So it's perfectly legal in one sense to say compareWithHundred "foobar", the type checker says that that expression's type is Ordering, but then it will fail later when it tries to check that there is a Num String instance.

I hope this helps.