There is a bit of overlap between Bifunctor
and Arrow
methods:
class Bifunctor p where
first :: (a -> a') -> p a b -> p a' b
second :: (b -> b') -> p a b -> p a b'
bimap :: (a -> a') -> (b -> b') -> p a b -> p a' b'
class Arrow (~~>) where
...
first :: (a ~~> a') -> (a, b) ~~> (a', b)
second :: (b ~~> b') -> (a, b) ~~> (a, b')
(***) :: (a ~~> a') -> (b ~~> b') -> (a, b) ~~> (a', b')
The Bifunctor
class comes with laws completely analogous to those of Functor
.
The Arrow
class comes with a number of laws different laws and a somewhat cryptic warning about (***)
: "Note that this is in general not a functor." Surprisingly (to me) there's only one law about (***)
:
first f >>> arr (id *** g) = arr (id *** g) >>> first f
The Arrow (->)
instance and the Bifunctor (,)
instance match up exactly, so that bimap @(,) = (***) @(->)
. Is there some special significance to this? Is there a meaningful hypothetical
class Foo (~~>) p where
biFoo :: (a ~~> a') -> (b ~~> b') -> p a b ~~> p a' b'
If so, does that admit functional dependencies?