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