Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a name for this subset of bifunctors?

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
like image 710
rlms Avatar asked Dec 28 '21 00:12

rlms


People also ask

Which set is a subset of set B?

Set A is said to be a subset of Set B if all the elements of Set A are also present in Set B. In other words, set A is contained inside Set B. Example: If set A has {X, Y} and set B has {X, Y, Z}, then A is the subset of B because elements of A are also present in set B.

How many types of subsets are there?

The number of proper subsets is 15. In set theory, a set X is defined as a subset of the other set Y, if all the elements of set X should be present in the set Y. This can be symbolically represented by X ⊂ Y What are the two classifications of subset? Define proper and improper subsets.

Which set is an improper subset of the power set?

Where, {}, {2}, {4}, {6}, {2,4}, {4,6}, {2,6} are the proper subsets and {2,4,6} is the improper subsets. Therefore, we can write {2,4,6} ⊆ P. Note: The empty set is an improper subset of itself (since it is equal to itself) but it is a proper subset of any other set. The power set is said to be the collection of all the subsets.

What does a ⊆ B mean in math?

A ⊆ B; which means Set A is a subset of Set B. Note: A subset can be equal to the set. That is, a subset can contain all the elements that are present in the set. The subsets of any set consists of all possible sets including its elements and the null set.


2 Answers

A type which is a Bifunctor need not have the same number of a values as b values. Consider, for example,

data TwoLists a b = TwoLists [a] [b]

It is easy to implement bimap, but othermap is a real problem, especially if one of the lists is empty.

othermap f (TwoLists [] (b:bs)) = TwoLists [] _

What can you do here? You need to call f to convert all the bs to a list of type [d], but you can only call that function if you have an a in hand.

Perhaps even worse is a type which doesn't really ever have b values at all:

data TaggedFunction k a b = TaggedFunction a (k -> b)
instance Bifunctor (TaggedFunction k) where
  bimap f g (TaggedFunction a b) = TaggedFunction (f a) (g . b)

How can you implement othermap for this type? You could update the function, because you have an a in hand and will have a b by the time you need a d. But there's no way for you to replace the a with a c, because you can't get hold of a b to call othermap'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 of as and bs in your structure, i.e. when your structure is some functor f wrapped around a tuple of type (a, b). For example, instead of TwoLists we could have defined

newtype PairList a b = PairList [(a, b)]

and that can have an othermap definition. But it would just be

othermap f (PairList vs) = PairList (fmap f vs)

Likewise instead of TaggedFunction we could have defined

newtype MultiFunction k a b = MultiFunction (k -> (a, b))

but the othermap definition is again just a wrapped call to fmap:

othermap f (MultiFunction g) = MultiFunction (fmap f g)

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:

newtype TupleFunctor f a b = TupleFunctor (f (a, b))

othermap :: Functor f => ((a, b) -> (c, d)) 
                      -> TupleFunctor f a b -> TupleFunctor f c d
othermap f (TupleFunctor x) = TupleFunctor (fmap f x)
like image 118
amalloy Avatar answered Oct 03 '22 04:10

amalloy


(Expanding on a comment by @glennsl...)

The type p a c "contains" both a and c.

But a function of type (a, c) -> (b, d) requires values of type a and c to be called, and a value of type p a c doesn't necessarily have both.

othermap @Either :: ((a, c) -> (b, d)) -> Either a c -> Either b d
othermap f (Left x) = ?
othermap f (Right y) = ?

There's no way for othermap to produce values of type b or d, because it can't call f in either case.

The type of the first argument implies a bifunctor that is isomorphic to (,), which is not true of all possible bifuntors. othermap is, in fact, strictly more specific than bimap. (There seems to be a contravariant relationship here that I won't try to make precise.)

like image 22
3 revs Avatar answered Oct 03 '22 04:10

3 revs