Why can't you compare Ints to Nums or Ords?

compare, haskell, typeclass

Solution

`>` expects two `Ord` instances of the same type.

ghci> :t (>)
(>) :: Ord a => a -> a -> Bool

That type signature is not the same as `(Ord a, Ord b) => a -> b -> Bool`, which would be the signature of a function which can compare any two instances of `Ord`. (A non-trivial version of such a function does not exist.)

The reason `>` places such a draconian requirement on the poor programmer is that different types may have different ordering semantics. How would you compare an `Int` to a `[Bool]`?* Even though they are both instances of `Ord`, it doesn't make sense to compare them and the compiler won't allow it:

ghci> 3 > [True, True, False]

<interactive>:6:1:
    No instance for (Num [Bool]) arising from the literal `3'
    Possible fix: add an instance declaration for (Num [Bool])
    In the first argument of `(>)', namely `3'
    In the expression: 3 > [True, True, False]
    In an equation for `it': it = 3 > [True, True, False]

Each instance of `Ord` defines its own version of `>`. That's why you can't compare an `Int` to a `Float`:

ghci> (3 :: Int) > (4 :: Float)

<interactive>:4:15:
    Couldn't match expected type `Int' with actual type `Float'
    In the second argument of `(>)', namely `(4 :: Float)'
    In the expression: (3 :: Int) > (4 :: Float)
    In an equation for `it': it = (3 :: Int) > (4 :: Float)

* To be pedantic, you could devise some way of representing an integer in binary as a list of booleans. Such a representation would be a good candidate for a `newtype` with its own instances of `Num` and `Ord`.

The reason `4 > 4.5` works is that the literal `4` is polymorphic. It can stand in for the '4' value of any numeric type:

ghci> :t 4
4 :: Num a => a

Similarly, `4.5` can take on any fractional type (`4.5 :: Fractional a => a`). The compiler is smart enough to realise that you are comparing a value of type "any number" to a value of type "any fractional number" and uses the most convenient concrete type available, which in this case is `Double`. (`Double` is declared as a `default` in the standard prelude.) So in the expression `4 > 4.5`, `4` and `4.5` will both be `Double`s.

You can force the comparison to use the `Ord` instance of a particular concrete type by supplying a type signature to one of the operands.

Problem

I have a function: ``` comp :: (Ord a) => a -> a -> Bool comp a b = if a > b then True else False ``` This works. But if I do this: ``` comp :: (Num a) => Int -> a -> Bool comp a b = if a > b then True else False ``` or this: ``` comp :: (Ord a) => Int -> a -> Bool comp a b = if a > b then True else False ``` I get an error message: Could not deduce (a ~ Int) Huh? Doesn't Num and Ord include Int? Aren't Num and Ord only supposed to include reals and not complex numbers? Why is it that in the interpreter I can compare any real to any int: ``` 4 > 4.5 False ``` But I'm not allowed to define a function that compares Ints to Nums or Ords?

Original source