Что означает "функция внутри функтора",

В теории категории функтор является гомоморфизмом между двумя категориями. В Haskell он сказал, что аппликативный функтор позволяет применять функции "внутри функтора". Можно ли перевести слова "функция внутри функтора" обратно в математику или дать другое представление? (Я знаю, что функтор может быть Maybe, [] и т.д., Но по-прежнему бороться за понимание этого понятия.)

Ответ 1

Моя теория категорий вообще невелика (я начал с программной стороны Haskell и недавно пытался узнать некоторые основы теории теорий некоторых ее концепций). Но вот что у меня есть:

В Haskell функтор является конструктором типа, что означает, что он отображает из общих типов в "типы в функторе".

В теории категорий функтор отображает объекты одной категории на объекты другой категории.

При применении теории категорий к Haskell мы предполагаем, что мы работаем с категорией Hask, категорией типов Haskell.

Таким образом, функторы Haskell не являются функциями общей теории категорий; все они сопоставляются с Hask подкатегорией Hask (поскольку тип f a для некоторого функтора f и произвольного типа a по-прежнему является типом Haskell). Например, функтор Maybe отображает объекты (типы) в Hask в категорию типов формы Maybe a.

Функции являются первоклассными в Haskell, поэтому типы функций являются совершенно обычными типами (и являются объектами Hask), поэтому функторы также отображают типы функций на "типы функций в функторе". Таким образом, фраза "функция внутри функтора" является сокращением для значения в типе, которое возникает в результате применения функтора к типу функции. например Just (+1) - одно конкретное значение в типе Maybe (Int -> Int), которое является объектом (типом), к которому функтор Maybe отображает объект Int -> Int.

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

Используя Maybe снова в качестве примера, если бы мы знали только, что это функтор, который дает нам соответствие между объектами Int -> Char и Maybe (Int -> Char), а также между объектами Int и Maybe Int и между объекты Char и Maybe Char. Но пока у нас есть возможность взять значение в Int -> Char и значение в Int и получить значение в Char, Maybe, являющееся функтором, не гарантирует, что у нас есть возможность выполнить некоторую соответствующую операцию со значением в Maybe (Int -> Char) и значением в Maybe Int.

Когда мы также знаем его как аппликативный функтор, то у нас есть возможность взять значение в Maybe (Int -> Char) и значение в Maybe Int и произвести значение в Maybe Char, и это удовлетворяет определенным свойствам по приложению значений Int -> Char до Int.

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

Ответ 2

Перевод Назад к математике

В замкнутой моноидальной категории существует понятие "экспонента", которое "интернализует" отношение морфизма. Затем вы можете оценить эти показатели. То есть у вас есть способ сказать (извините мое понятие, Stackoverflow не хватает mathjax)

eval : (a ~> b,a) -> b

а также мета-операции для currying и uncurrying.
"Аппликативный функтор" отображает экспоненты "применимым" способом, F (a ~> b) можно комбинировать с F a, чтобы получить F b. Это связано с тем, что аппликативные функторы являются моноидальными функторами, поэтому они имеют операцию (в целевой категории)

f a -> f b -> f (a,b)

который, когда вы также fmap eval, дает вам ap из Haskell.

Я сомневаюсь, что это было полезно,

Haskell

Лучший способ понять аппликативный функтор - посмотреть на тип

class Functor f => Applicative f where
  pure :: a -> f a
  <*>  :: f (a -> b) -> f a -> f b

тривиальный пример

newtype Id a = Id a
instance Applicative Id where
  pure a = Id a
  Id f <*> Id a = Id (f $ a)

Id также является Monad. На самом деле все Monad являются Applicative.

pure = return
mf <*> mx = do f <- mf
               x <- mx
               return (f x)

более интересным примером является бесконечная последовательность

data Seq a = Seq a (Seq a)
instance Applicative Seq where
  pure a = Seq a (pure a)
  (Seq f fs) <*> (Seq x xs) = Seq (f x) (fs <$> xs)

Вы можете думать об этом как о эквиваленте zipWith $ в списках. Все Monad являются Applicative, но я думаю, что бесконечная последовательность интересна, потому что соответствующий экземпляр монады... не очевидный (и довольно медленный). Он будет оставлен как упражнение для читателя (кстати, я утомляю этот пример/упражнение от чего-то, что я помню, читающего, что, по-моему, на этом сайте написал питомник).