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.