I am in need of the following class of functions:
class InterleavedHomomorphic x where
interleaveHomomorphism :: (forall a . f a -> g a) -> x f -> x g
Obviously the name I invented for it is not in any way an official term for anything, and the type class above is not very elegant. Is this a concept that has a name, or even an implementation in some library? Is there some more reasonable way of doing this?
The purpose of this function would be that I have some context f
that annotates some data (Foo
and Bar
are just random example data structures for the sake of this question):
data Foo f = One (f (Bar f)) | Product (f (Foo f)) (f (Foo f))
data Bar f = Zero | Succ (f (Bar f))
I would like to transform the context of the data in a polymorphic way; by only knowing the homomorphism between the contexts and not (necessarily) caring about the data itself. This would be done by providing instance InterleavedHomomorphic Foo
and instance InterleavedHomomorphic Bar
in the example above.
So, assuming f
and g
are proper functors, forall a. f a -> g a
is a natural transformation. We could make it a bit prettier:
type f ~> g = forall a. f a -> g a
Natural transformations like this let us form a category of Haskell Functors, so what you have is a functor from that to some other category.
Following the steps of normal Haskell Functors, it would perhaps make sense to have x
be an endofunctor, mapping Functors to other Functors. This is similar, but not identical, to what you have:
class FFunctor x where
ffmap :: (f ~> g) -> (x f ~> x g)
However, in your case x f
and x g
are not functors, and x f -> x g
is a normal function rather than a natural transformation. Still, the pattern is close enough to be intriguing.
With this in mind, it seems that x
is still an example of a functor, just between two different categories. It goes from the category of Functors to the category of x
s with different structures. Each possible x
, like Foo
, forms a category with objects like Foo []
and Foo Maybe
and transformations between them (Foo [] -> Foo Maybe
). Your interleaveHomomorphism
function "lifts" natural transformations into these x-morphisms
, just like fmap
"lifts" normal (a -> b
) functions into functions in the image of the functor (f a -> f b
).
So yeah: your typeclass is a functor just like Functor
, except between two different categories. I don't know of a specific name for it, largely because I don't know a specific name for constructs like x
.
More generally, I'm not even sure a specific name would make sense. At this point, we'd probably like a nice generic functor typeclass that go between any two categories. Maybe something like:
class (Category catA, Category catB) => GFunctor f catA catB where
gfmap :: catA a b -> catB (f a) (f b)
This probably already exists in a library somewhere.
Unfortunately, this particular approach to defining different functors would require a bunch of extra newtype noise since (->)
is already a category. In fact, getting all the types to line up properly is going to be a bit of a pain.
So it's probably easiest just to call it an XFunctor
or something. Besides, just imagine the pun potential!
EDIT: It looks like categories
provides a CFunctor
type like this, but a bit cleverer:
class (Category r, Category s) => CFunctor f r s | f r -> s, f s -> r where
cmap :: r a b -> s (f a) (f b)
However, I'm not certain that even this is general enough! I think that we might want it to be more polymorphic over kinds too.