I am trying to model a generic Range type with the following definition:
data Range a = Range
{ lower :: a
, upper :: a }
I added a smart constructor (and only exported it without the data constructor) so that consumers cannot accidentally create a Range with its lower field larger than its upper field:
range :: Ord a => a -> a -> Range a
range lower upper =
if lower > upper
then Range upper lower
else Range lower upper
This is all good and I moved on with deriving a Functor instance of it:
instance Functor Range where
fmap f (Range lower upper) = Range (f lower) (f upper)
This became problematic because I can do:
main :: IO ()
main = do
let r1 = range 1 2
r2 = fmap negate r1
return ()
-- Now r2 has its upper field less than its lower field
My naive attempt would be to use the smart constructor range in the implementation of fmap like:
instance Functor Range where
fmap f (Range lower upper) = range (f lower) (f upper)
However, this does not compile as f lower and f upper are not constrained to have an Ord a instance.
How can I fix this so I can maintain the type invariant of having lower always less than or equal to upper?