Существует небольшое совпадение между Bifunctor и Arrow:
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')
Класс Bifunctor поставляется с законами, полностью аналогичными законам Functor.
Класс Arrow поставляется с рядом законов, различных законов и несколько загадочным предупреждением о (***): "Обратите внимание, что это вообще не функтор". Удивительно (для меня) там только один закон о (***):
first f >>> arr (id *** g) = arr (id *** g) >>> first f
Экземпляр Arrow (->) экземпляр Bifunctor (,) точно совпадают, поэтому bimap @(,) = (***) @(->). Есть ли какое-то особое значение для этого? Есть ли значимые гипотетические
class Foo (~~>) p where
biFoo :: (a ~~> a') -> (b ~~> b') -> p a b ~~> p a' b'
Если так, это допускает функциональные зависимости?