Reputation: 23135
Functor in Control.Categorical.Functor has the following definition:
class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where
fmap :: r a b -> t (f a) (f b)
But lets say I want to have a functor from ordinary functions to Kleisli arrows (this is perhaps a silly example) .
I'd want a type like this:
fmap :: (Monad m) => (a -> b) -> Kleisli m a b
Well I can let r = (->)
, t = Kleisli m
to get:
fmap :: (Monad m) => (a -> b) -> Kleisli m (f a) (f b)
But then, what's f
?! I really just want it to disappear. I could use the Identity functor by letting f = Identity
but then I get:
fmap :: (Monad m) => (a -> b) -> Kleisli m (Identity a) (Identity b)
which would require some messy unwrapping.
I then thought of defining Functor like this:
class (Category r, Category t) => Functor r t where
type family F r t x :: *
fmap :: r a b -> t (F r t a) (F r t b)
This allows me to define a Functor instance for Kleisli as follows (without an ugly Identity wrapper):
instance (Monad m) => Functor (->) (Kleisli m) where
type F (->) (Kleisli m) a = a
fmap f = Kleisli (return . f)
And after this, I'm pretty sure I'm at:
fmap :: (Monad m) => (a -> b) -> Kleisli m a b
Which is good.
Now, there's one issue I can identify straight away namely, for a given r
and t
parameters to Functor
, the original class definition allows multiple options for f
, whereas with my definition, r
and t
determine f
. This is a serious problem, as if I define say:
fmap :: (a -> b) -> (Maybe a -> Maybe b)
I can't then define:
fmap :: (a -> b) -> ([a] -> [b])
As in both cases, r = (->)
and t = (->)
. So currently my Functor
doesn't even replace the original Prelude version.
So there's some questions I now have:
r
and t
do not determine f
(like the original version)? Or would this require Injective Type Families (I'm happy to compile head to try this if this is the case). f
and r
determines t
and also f
and t
determines r
?I'm sorry the last few questions are a bit vague, I understand that type inference vs generality is often a tradeoff, but I'm just looking for some thoughts on it in this particular case.
(This question partly follows on from answers to this question)
Upvotes: 2
Views: 85
Reputation: 120751
The closest you could get would be
class (Category r, Category t) => Functor
(f :: *) (r :: *->*->*) (t :: *->*->*) where
type F f x :: *
fmap :: Tagged f ( r a b -> t (F f a) (F f b) )
instance Functor [()] (->) (->) where
type F [()] x = [x]
fmap = Tagged map
instance (Monad m) => Functor (Kleisli m () ()) (->) (Kleisli m) where
type F (Kleisli m () ()) x = x
fmap = Tagged $ \f -> Kleisli $ return . f
Upvotes: 3