Что такое определение Applicative Functor из точки зрения теории категорий?

Мне удалось сопоставить определение функтора из теории категорий с определением Haskell следующим образом: поскольку объекты Hask являются типами, функтор F

  • сопоставляет каждый тип a из Hask новому типу F a, грубо говоря, добавляя к нему букву «F».
  • отображает каждый морфизм a -> b из Hask на новый морфизм F a -> F b, используя fmap :: (a -> b) -> (f a -> f b).

Все идет нормально. Теперь я перехожу к Applicative и не могу найти упоминания о такой концепции в учебниках. Глядя на то, что он добавляет к Functor, ap :: f (a -> b) -> f a -> f b, я попытался придумать собственное определение.

Во-первых, я заметил, что, поскольку (->) также является типом, морфизмы Hask также являются его объектами. В свете этого я высказал предположение, что аппликативный функтор является функтором, который также может отображать «стрелочные» объекты исходной категории в морфизмы целевой категории.

Это правильная интуиция? Можете ли вы дать более формальное и строгое определение?


person arrowd    schedule 26.01.2016    source источник
comment
теория. stackexchange.com/questions/12412/   -  person n. 1.8e9-where's-my-share m.    schedule 26.01.2016


Ответы (2)


Ключ к пониманию аппликативных функторов - это выяснить, какую структуру они сохраняют.

Регулярные функторы сохраняют базовую категориальную структуру: они отображают объекты и морфизмы между категориями и сохраняют законы категории (ассоциативность и идентичность).

Но у категории может быть больше структуры. Например, это может позволить определение отображений, которые похожи на морфизмы, но принимают несколько аргументов. Такие сопоставления определяются каррированием: например, функция двух аргументов определяется как функция одного аргумента, возвращающая другую функцию. Это возможно, если вы можете определить объект, представляющий тип функции. В общем, этот объект называется экспонентой (в Haskell это просто тип b->c). Тогда мы можем иметь морфизмы от одного объекта к экспоненциальному и называть это морфизмом с двумя аргументами.

Традиционное определение аппликативного функтора в Haskell основано на идее отображения функций с несколькими аргументами. Но есть эквивалентное определение, которое разделяет функцию с несколькими аргументами по другой границе. Вы можете рассматривать такую ​​функцию как отображение продукта (пары в Haskell) на другой тип (здесь c).

a -> (b -> c)  ~  (a, b) -> c

Это позволяет нам рассматривать аппликативные функторы как функторы, сохраняющие продукт. Но продукт - лишь один из примеров того, что называется моноидальной структурой.

В общем, моноидальная категория - это категория, снабженная тензорным произведением и единичным объектом. В Haskell это может быть, например, декартово произведение (пара) и тип единицы (). Обратите внимание, однако, что моноидальные законы (ассоциативность и единичные законы) действительны только с точностью до изоморфизма. Например:

(a, ())  ~  a

Тогда аппликативный функтор можно определить как функтор, сохраняющий моноидальную структуру. В частности, следует сохранить агрегат и изделие. Не имеет значения, выполняем ли мы «умножение» до или после применения функтора. Результаты должны быть изоморфными.

Однако полноценный моноидальный функтор нам не нужен. Все, что нам нужно, это два морфизма (в отличие от изоморфизмов) - один для умножения и один для единицы. Такой функтор, который наполовину сохраняет моноидальную структуру, называется слабым моноидальным функтором. Отсюда альтернативное определение:

class Functor f => Monoidal f where
  unit :: f ()
  (**) :: f a -> f b -> f (a, b)

Легко показать, что Monoidal эквивалентно Applicative. Например, мы можем получить pure из unit и наоборот:

pure x = fmap (const x) unit
unit = pure ()

Прикладные законы просто следуют из сохранения моноидных законов (ассоциативности и единичных законов).

В теории категорий сохранение моноидальной структуры связано с тензорной силой, поэтому аппликативный функтор также известен как сильный слабый моноидальный функтор. Однако в Hask каждый функтор имеет каноническую силу по отношению к продукту, поэтому это свойство ничего не добавляет к определению.

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

person Bartosz Milewski    schedule 27.01.2016
comment
Что это за сила? - person dfeuer; 28.01.2016
comment
Да, если вы можете добавить немного о том, что означает здесь сила, это проясняет; особенно потому, что ответ leftaroundabout ссылается на en.wikipedia.org/wiki/Monoidal_functor, который, по-видимому, определяет сильную моноидальные функторы означают моноидальный функтор с некоторыми предполагаемыми ограничениями, а слабые моноидальные функторы означают отсутствие дополнительных предположений, поэтому в этой терминологии сильный нестрогий моноидальный функтор не имеет смысла. - person Ben; 28.01.2016
comment
Лично я предпочитаю думать о аппликативных функторах как о «замкнутых функторах», а не как о моноидальных. Тот факт, что они являются моноидальными, более или менее случайен и обусловлен сохранением экспонент, поэтому «моноидальное» кодирование вещей кажется таким беспорядочным, в то время как комбинатор (<*>) :: f (a -> b) -> f a -> f b, который мы используем, является в точности отображением экспонент! Другой способ думать об аппликативе - это как моноидный объект относительно (ковариантной) дневной свертки. Преимущество этой точки зрения состоит в том, что она освещает путь к поиску контравариантной формы Applicative. - person Edward KMETT; 28.01.2016
comment
Для меня это имело гораздо больше смысла, когда я мысленно не торопился (**) в (f a, f b) -> f (a, b). Интересно, почему вы не написали это в первую очередь. - person arrowd; 04.02.2016
comment
@arrowd: на самом деле, возможно, даже «более глубокий» вариант - это ((a,b)->c) -> (f a,f b)->f c, отражающий, что функтор переводит моноидальную структуру одной категории в структуру другой (хотя обе категории здесь Hask). - person leftaroundabout; 17.02.2016

Вы правы, Applicative переводится менее прямолинейно, чем Functor или Monad. Но по сути это класс моноидальных функторов:

class Functor f => Monoidal f where
  pureUnit :: f ()
  fzip :: f a -> f b -> f (a,b)

Исходя из этого, вы можете определить - в Hask -

pure x = fmap (const x) pureUnit

а также

fs <*> xs = fmap (uncurry ($)) $ fzip fs xs

См. этот ответ для полного доказательства того, что Applicative и Monoidal действительно эквивалентны.

person leftaroundabout    schedule 26.01.2016