fun
has three arguments and a result. So initially the compiler assumes they might each be a different type:
fun :: alpha -> beta -> gamma -> delta -- the type vars are placeholders
Ignoring the guards, look at the rhs result of the equations: they each must be type delta
. So set up a series of type-level equations from the term-level equations. Use ~
between types to say they must be the same.
- The first equation has result
b
, so b
's type must be same as the result, i.e. beta ~ delta
.
- The third equation has result
c
, so c
's type must be the same as the result, gamma ~ delta
.
- The second equation has rhs
+
operator :: Num a => a -> a -> a
. We'll come back to the Num a =>
. This is saying +
has two arguments and a result, all of which are same type. That type is the result of fun
's rhs so must be delta
. The second arg to +
is b
, so b
's type must be same as the result, beta ~ delta
. We already had that from the first equation, so this is just confirming consistency.
- The first arg to
+
is a
, so a
's type must be same again, alpha ~ delta
.
We have alpha ~ beta ~ gamma ~ delta
. So go back to the initial signature (which was as general as possible), and substitute equals for equals:
fun :: (constraints) => alpha -> alpha -> alpha -> alpha
Constraints
Pick those up on the fly from the operators.
- We already saw
Num
because of operator +
.
- The first equation's
a == c
gives us Eq
.
- The second equation's
b < 0
gives us Ord
.
- Actually the appearance of
0
gives us another Num
, because 0 :: Num a => a
, and < :: Ord a => a -> a -> Bool
IOW the arguments to <
must be same type and same constraints.
So pile up those constraints at the front of fun
's type, eliminating duplicates
fun :: (Num alpha, Eq alpha, Ord alpha) => alpha -> alpha -> alpha -> alpha
Is that what you're favourite compiler is telling you? It's probably using type variable a
rather than alpha
. It's probably not showing Eq alpha
.
Eliminating unnecessary superclass constraints
Main> :i Ord
...
class Eq a => Ord a where
...
The Eq a =>
is telling every Ord
type must come with an Eq
already. So in giving the signature for fun
, the compiler is assuming away its Eq
.
fun :: (Num a, Ord a) => a -> a -> a -> a
QED