Reputation: 865
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?
Upvotes: 3
Views: 1022
Reputation: 44634
>
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.
Upvotes: 11
Reputation: 27217
Ok, but let's say you did want to write the function
comp :: (Num a, Ord a) => Int -> a -> Bool
The function you need is fromIntegral :: (Integral a, Num b) => a -> b
. One of the properties of a Num
type in Haskell is that it must implement a sane version of this function. The resulting implementation would be
comp n x = fromIntegral n < x
Upvotes: 3
Reputation: 139840
All the comparison operators in Ord
have the type Ord a => a -> a -> Bool
, so you can only ever compare two values of the same type.
Why is it that in the interpreter I can compare any real to any int:
4 > 4.5 False
You're not. You are comparing two Double
s. Integer literals are overloaded in Haskell, so 4
can have any Num
type depending on the context.
> :t 4
4 :: Num a => a
The same is true for decimal literals, which can be any Fractional
type.
> :t 4.5
4.5 :: Fractional a => a
Based on these constraints, and the fact that the two sides should have the same type, it defaults both sides to Double
.
> :set -fwarn-type-defaults
> 4 > 4.5
<interactive>:6:5: Warning:
Defaulting the following constraint(s) to type `Double'
(Fractional a0)
arising from the literal `4.5' at <interactive>:6:5-7
(Num a0) arising from the literal `4' at <interactive>:6:1
(Ord a0) arising from a use of `>' at <interactive>:6:3
In the second argument of `(>)', namely `4.5'
In the expression: 4 > 4.5
In an equation for `it': it = 4 > 4.5
<interactive>:6:5: Warning:
Defaulting the following constraint(s) to type `Double'
(Fractional a0)
arising from the literal `4.5' at <interactive>:6:5-7
(Num a0) arising from the literal `4' at <interactive>:6:1
(Ord a0) arising from a use of `>' at <interactive>:6:3
In the second argument of `(>)', namely `4.5'
In the expression: 4 > 4.5
In an equation for `it': it = 4 > 4.5
Upvotes: 4
Reputation: 116139
The type
comp :: (Num a) => Int -> a -> Bool
states that comp
can work on an Int
and any numeric type, i.e., a numeric type chosen by who calls this function. Since the caller can choose a complex type, it is impossible to implement comp
in a meaningful way.
The type
comp :: (Ord a) => Int -> a -> Bool
states that comp
can work on an Int
and any ordered type, i.e., an ordered type chosen by who calls this function. Since the caller can choose String
, or (Int,Int)
, it is impossible to implement comp
in a meaningful way.
Upvotes: 3