Reputation: 105
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.
Upvotes: 5
Views: 744
Reputation: 102006
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
.)
Upvotes: 12