I love mapped
from the lens package.
mapped :: Prelude.Functor f => Setter (f a) (f b) a b
However I have recently started to use Functor
from the category package (from here out I will refer to category's Functor
just as Functor
and use Prelude.Functor
otherwise), so my mapped
no longer works.
So I would like to make a version of mapped
that can work with Functor
. As a refresher for all who need it, the kind signature of Functor
looks like:
class (Category s, Category t) => Functor (s :: α -> α -> *) (t :: β -> β -> *) (f :: α -> β) where
map :: s a b -> t (f a) (f b)
This takes two of the (->)
s in the vanilla fmap
and replaces them with s
and t
which satisfy Category
.
So if we would like to make a replacement for mapped
we need to replace the appropriate (->)
with generic Category
satisfying types. So we dealias the Setter
:
mapped ::
Prelude.Functor f =>
( forall g. Settable g =>
(a -> g b) -> (f a) -> g (f b)
)
In order to move forward we are going to look at over
since we would want it to be that:
over mapped = map
Now we look at the implementation of over
(unpacking ASetter
):
over :: ((a -> Identity b) -> s -> Identity t) -> (a -> b) -> s -> t
over l f = runIdentity #. l (Identity #. f)
We can get a little bit of information out of this. We know the types of runIdentity
, (#.)
and the goal. If we work backwards
(#.) runIdentity (mapped (Identity #. f)) ::
Category t => t (f a) (f b)
mapped (Identity #. f) ::
( Category t
, Profunctor t
, Coercible (f b) z
)
=> t (f a) z
Which is good evidence that the third (->)
should be replaced with a generic category, and decent evidence that the second should not.
mapped ::
( Functor s t f
, Category s
, Category t
) =>
( forall g. Settable g =>
(s a (g b)) -> t (f a) (g (f b))
)
And here I am stuck. I feel as if I am pressing up against my conceptual backing here. I don't know if this type is correct or if I am missing something. Even if I did know the type I'm not sure how I would even implement mapped
or over
. I am used to using the prebuilt combinators out of the lens package to build my lenses and I don't think those are going to help me once I am no longer using a Setter
.
How can I get from where I am to a working mapped
implementation for Functor
?
I believe the type is definitely correct. Poking around in the code,
mapped
is defined aswhere
taintedDot
,untaintedDot
are methods ofSettable
. As @leftaroundabout's comment makes the point, this is probably the difficulty of the translation - you would need an equivalent class for categories, though exactly what it would mean is beyond me.A naive guess would be
which look a lot like
Monad
andComonad
operations, so maybeAlternatives...
That said, you could cheat - the
Profunctor
equivalent inCategory
is just anArrow
, since you can lift Hask arrows to categorical ones. If yourCategory
s are alsoArrow
s, then you could doThen sneak in the
Cheat