Suppose I’m writing a function that takes a list of integers and returns only those integers in the list that are less than 5.2. I might do something like this:
belowThreshold = filter (< 5.2)
Easy enough, right? But now I want to constrain this function to only work with input lists of type [Int] for design reasons of my own. This seems like a reasonable request. Alas, no. A declaration that constraints the types as so:
belowThreshold :: [Integer] -> [Integer]
belowThreshold = filter (< 5.2)
Causes a type error. So what’s the story here? Why does doing filter (< 5.2) seem to convert my input list into Doubles? How can I make a version of this function that only accepts integer lists and only returns integer lists? Why does the type system hate me?
Check the inferred type of belowThreshold in ghci before adding your annoatation:
It sounds like you expected
Num a => [a] -> [a]when you said “constrain this function”. You are actually changing the type of the function when you add the[Integer] -> [Integer]annotation.To make this work, use an explicit conversion:
Now
belowThreshold :: [Integer] -> [Integer]like you wanted. But the integers are converted to doubles before comparison to 5.2.So why do you need the conversion? The type error probably misled you: the list of Integers wasn’t being converted to Doubles by comparison to 5.2, the real problem is that only Doubles can be compared to Doubles, so you must pass a list of Doubles to
belowThreshold. Haskell has no implicit conversions, not even between numbers. If you want conversions, you have to write them yourself.Well, from the perspective of the type system, no. Is this reasonable code?
What about this?
All of these values are instances of
Ord, but you can’t use them together with(<). Haskell has no implicit conversions. So even if two values are both instances ofNumas well asOrd, you won’t be able to compare them with(<)if they are of different types.