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