Confusion with Haskell type inference

haskell, type-inference

Solution

Consider the expression that doesn't work

isLongerThanN' :: Integral n => n -> [a] -> Bool
isLongerThanN' n xs = length xs > n

`n` can be any integer-y type, so it can be passed an `Integer` or `Word` or `Int`. `(>)` has type `Ord a => a -> a -> Bool` so both its left and right operand have to be of the same type. `length xs` returns an `Int` so this type has to be that. But, `n` can be any `Integral`, not necessarily `Int`, so we need some way of allowing `n` to be converted to an `Int`. This is what `fromIntegral` does (the fact that it also allows `n` to be any `Num` is basically irrelevant).

We could expand the working version to look like:

toInt :: Integral n => n -> Int
toInt = fromIntegral

isLongerThanN :: Integral n => n -> [a] -> Bool
isLongerThanN n xs = length xs > toInt n

which makes it clearer that we're using a specialised version of `fromIntegral`.

(Note that `isLongerThanN n xs = fromIntegral (length xs) > n` also works, because it allows the result of `length` to match up with the type of `n`.)

Problem

I don't understand why the following function works: ``` isLongerThanN :: Integral n => n -> [a] -> Bool isLongerThanN n xs = length xs > fromIntegral n ``` but the following doesn't: ``` isLongerThanN' :: Integral n => n -> [a] -> Bool isLongerThanN' n xs = length xs > n ``` which throws the error ``` Could not deduce (n ~ Int) from the context (Integral n) bound by the type signature for isLongerThanN' :: Integral n => n -> [a] -> Bool at blah.hs:140:1-35 `n' is a rigid type variable bound by the type signature for isLongerThanN' :: Integral n => n -> [a] -> Bool at blah.hs:140:1 In the second argument of `(>)', namely `n' In the expression: length xs > n In an equation for `isLongerThanN'': isLongerThanN' n xs = length xs > n ``` (which I've likely misunderstood) If anything, I would expect it to be the other way around, since fromIntegral is effectively broadening variable n's type.

Original source