Что такое определение Аппликативного Функтора из теории категорий POV?

Я смог отобразить определение Функтора из теории категорий в определение Хаскелла следующим образом: поскольку объекты 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 являются объектами этого тоже. В свете этого я высказал предположение, что аппликативный функтор является функтором, который также может отображать "стрелочные"-объекты исходной категории в морфизмы целевой.

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

2 ответа

Решение

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

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

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

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

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

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

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

(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 каждый функтор обладает канонической силой по отношению к продукту, поэтому это свойство ничего не добавляет к определению.

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

Ты прав, 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
Другие вопросы по тегам