Между методами 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'
Если да, допускает ли это функциональные зависимости?