Bifunctors have a map function with this signature:
bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
You could also have a map like this:
othermap :: ((a, c) -> (b, d)) -> p a c -> p b d
Types with this function are a strict subset of bifunctors (you can always define bimap
using othermap
but not vice versa). Is there a name for the second signature?
Follow-up: what about this intermediate function?
halfothermap :: ((a, c) -> b) -> (c -> d) -> p a c -> p b d
A type which is a Bifunctor need not have the same number of
a
values asb
values. Consider, for example,It is easy to implement
bimap
, butothermap
is a real problem, especially if one of the lists is empty.What can you do here? You need to call
f
to convert all thebs
to a list of type[d]
, but you can only call that function if you have ana
in hand.Perhaps even worse is a type which doesn't really ever have
b
values at all:How can you implement
othermap
for this type? You could update the function, because you have ana
in hand and will have ab
by the time you need ad
. But there's no way for you to replace thea
with ac
, because you can't get hold of ab
to callothermap
's function with.So you can't put this function in Bifunctor. Perhaps you're asking, why not put this in a new class? I think leftroundabout is right that the class is too constraining to be useful.
othermap
can be defined only when you have the same number ofa
s andb
s in your structure, i.e. when your structure is some functorf
wrapped around a tuple of type(a, b)
. For example, instead of TwoLists we could have definedand that can have an
othermap
definition. But it would just beLikewise instead of TaggedFunction we could have defined
but the
othermap
definition is again just a wrapped call tofmap
:So perhaps the best way to imagine defining this abstraction would be as, not a typeclass function, but an ordinary function that operates over a type that captures this composition: