Бифунктор против стрелочных методов

Между методами 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'

Если да, допускает ли это функциональные зависимости?


person dfeuer    schedule 12.07.2019    source источник
comment
читать о Profunctor   -  person xgrommx    schedule 12.07.2019


Ответы (2)


Arrow является (несколько искаженным) предшественником класса декартовских закрытых категорий или, по крайней мере, декартовы моноидальные категории. В частности, для моноидальных категорий, тензорное произведение которых равно (,) и единичный элемент ().

Напомним, что моноидальная категория характеризуется тензорным произведением как бифунктором, поэтому существует связь между Arrow и Bifunctor.

*** на самом деле имеет больше законов, чем вы перечислили, только вместо этого библиотека предпочитает формулировать их в терминах first. Вот эквивалентное определение класса:

class (Category k, Category k') => EnhancedCategory k k' where
  arr :: k a b -> k' a b
  -- arr id ≡ id
  -- arr (f . g) = arr f . arr g
class (EnhancedCategory (->) a) => Arrow a where
  (***) :: a b c -> a b' c' -> a (b,b') (c,c')
  -- (f***id) . (g***id) ≡ (f.g)***id
  -- (id***f) . (id***g) ≡ id***(f.g)
  -- arr fst . (f***id) ≡ f . arr fst
  -- arr snd . (id***g) ≡ g . arr snd
  -- ¿ arr swap . (f***g) ≡ (g***f) . arr swap ?
  -- ((f***g)***h) . assoc ≡ assoc . (f***(g***h))
  diag :: a b (b,b)

first :: Arrow a => a b c -> a (b,d) (c,d)
first f = f***id
second :: Arrow a => a b c -> a (d,b) (d,c)
second g = id***g
(&&&) :: Arrow a => a b c -> a b d -> a b (c,d)
f&&&g = (f***g) . diag

Кстати, также можно удалить arr для поднятия чистых функций и вместо этого дать суперклассу только выделенные методы fst, snd и assoc. Я называю этот класс Cartesian. Это позволяет определять категории «стрелок», которые не содержат произвольные функции Haskell; линейные карты являются важным примером.

person leftaroundabout    schedule 12.07.2019
comment
Я еще многого не понимаю, но позвольте мне начать с вопроса, что такое EnhancedCategory. - person dfeuer; 12.07.2019
comment
class EnhancedCategory k k' where arr :: k a b -> k' a b. На самом деле я не уверен, установлен ли этот термин или я придумал новый в constrained-categories. - Отредактировал это в ответ. - person leftaroundabout; 12.07.2019
comment
arr fst . (f***g) ≡ f . arr fst это (и два следующих за ним) не подходит для экземпляра Kleisli m стрелки. - person Li-yao Xia; 13.07.2019
comment
Хм, ты прав; это на самом деле кажется специфичным для f***id (т.е. для first f). Также не уверен насчет закона о свопах... - person leftaroundabout; 13.07.2019
comment
Итак, я предполагаю, что может существовать класс MonoidalCategory с явным тензорным произведением. А фундепса нет? - person dfeuer; 13.07.2019
comment
Вы имеете в виду, например, hackage.haskell.org/ пакет/категории-1.0.7/документы/ ? - person leftaroundabout; 14.07.2019
comment
Разве EnhancedCategory не просто другое имя для Functor (обобщенное для не-Hask)? - person Benjamin Hodgson♦; 15.07.2019
comment
@BenjaminHodgson да, это своего рода «две категории с одним каноническим функтором между ними». Если есть имя для этого в математике, я хотел бы знать. Functor ни в коем случае нельзя использовать для этого класса... - person leftaroundabout; 15.07.2019

Arrow эквивалентен Strong + Category.

Вы можете выбрать другое понятие силы чтобы получить другой типа Arrow.

class Category a => ArrowChoice a where
    arr :: (b -> c) -> a b c
    (+++) :: a b c -> a b' c' -> a (Either b b') (Either c c')

Другими словами, тензорное произведение вашей декартовой замкнутой категории не обязательно должно быть точно (,). Любой тензорный продукт, который вы можете придумать, имеет соответствующее понятие силы, каждое из которых даст вам соответствующее разнообразие Arrow.

Примечательно, что многие профункторы являются одновременно Strong и Choice, поэтому ваш Foo (который в основном обобщает Strong по тензорному произведению p) не имеет функциональной зависимости.

Модуль Control.Arrow в base, к сожалению, немного путает иерархию (например, их ArrowChoice имеет Arrow в качестве суперкласса).

person Benjamin Hodgson♦    schedule 15.07.2019