I have defined the following data type:
data Probability a = PD { mass :: [(a, Ratio Int)] }
Now I want to write that it is an instance of
Sadly, you can't do that—Functor instances must accept any kind of mapping function without restriction.
You can kind of fake it, though.
newtype PF a = PF { unPF :: forall r . Eq r => (a -> r) -> Probability r }
instance Functor PF where
fmap f (PF p) = PF (\mp -> p (mp . f))
Here, all of the functions that would be mapped over Probability have been "deferred" by PF. We run them all at once by "lowering" back into Probability when possible
lowerPF :: Eq a => PF a -> Probability a
lowerPF pf = unPF pf id
And in order to convert a Probability into a fmappable PF we must "lift" it
liftPF :: Probability a -> PF a
liftPF p = PF $ \mp -> PD (collect $ map (first mp) (mass p))
What you're writing is not a Functor. A Functor's fmap must support arbitrary value types being mapped, not just those that satisfy a certain constraint. You can make it an instance of a more general concept though. For example, the package constrained-categories defines a class of constrained functors.