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))