5
votes

For the following trivial function definitions:

printLength1::(Num a)=>String->a
printLength1 s = length s


printLength2::String->Int
printLength2 s = length s

Why are they not the same ? In what situations i should choose one over the other?

And i get this error for printLength1:

Couldn't match type `a' with `Int'
      `a' is a rigid type variable bound by
          the type signature for rpnc :: String -> a at test.hs:20:1
    In the return type of a call of `length'
    In the expression: length s
    In an equation for `rpnc': rpnc s = length s

I understand this error. But how can i fix this ? I've already read some posts here about rigid type variable but still couldn't understand how to fix it.

2

2 Answers

9
votes

The first type signature is more general. It means the result can be any Num--it is polymorphic on its return type. So the result of your first function could be used as an Int or an Integer or any other Num instance.

The problem is that length returns an Int rather than any Num instance. You can fix this using fromIntegral:

printLength1 :: Num a => String -> a
printLength1 s = fromIntegral $ length s

Note that the signature of fromIntegral . length (which is the point-free version of the code above) is Num c => [a] -> c. This matches the signature you specified for your printLength1 function.

7
votes

Quoting LearnYouAHaskell.com:

Note: This function has a type of numLongChains :: Int because length returns an Int instead of a Num a for historical reasons. If we wanted to return a more general Num a, we could have used fromIntegral on the resulting length.