Ответ 1
Неясно, к чему "аппликативный" используется для обозначения, не зная контекста.
Если это действительно не относится к аппликативным функторам (т.е. Applicative
), то это, вероятно, относится к самой форме приложения: f a b c
является аппликативной формой, и именно здесь аппликативные функторы получают свое имя от: f <$> a <*> b <*> c
аналогично. (Действительно, скобки идиомы принимают это соединение дальше, позволяя вам записать его как (| f a b c |)
.)
Аналогичным образом, "аппликативные языки" могут быть противопоставлены языкам, которые в основном не основаны на применении функции к аргументу (обычно в форме префикса); например, конкатенационные ( "основанные на стеке" ) языки не применяются.
Чтобы ответить на вопрос о том, почему аппликативные функторы называются то, что они в глубине, я рекомендую читать
Аппликационное программирование с эффектами; основная идея состоит в том, что многие ситуации требуют чего-то вроде "расширенного приложения": применение чистых функций в каком-то эффектном контексте. Сравните эти определения map
и mapM
:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
mapM _ [] = return []
mapM f (x:xs) = do
x' <- f x
xs' <- mapM f xs
return (x' : xs')
с mapA
(обычно называемый traverse
):
mapA :: (Applicative f) => (a -> f b) -> [a] -> f [b]
mapA _ [] = pure []
mapA f (x:xs) = (:) <$> f x <*> mapA f xs
Как вы можете видеть, mapA
гораздо более кратким и, более очевидно, связано с map
(тем более, если вы используете префиксную форму (:)
в map
тоже). В самом деле, использование апликативного функторного обозначения, даже если у вас есть полный Monad
, распространен в Haskell, так как он часто намного более ясен.
Также полезно посмотреть на определение:
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Сравните тип (<*>)
с типом приложения: ($) :: (a -> b) -> a -> b
. Какие предложения Applicative
представляют собой обобщенную "отмененную" форму приложения, а ее код написан в аппликативном стиле.
Более формально, как упоминалось в статье и обозначено ertes, Applicative
является обобщением комбайнов ; pure
является обобщением K :: a -> (r -> a)
(aka const
), а (<*>)
является обобщением S :: (r -> a -> b) -> (r -> a) -> (r -> b)
. Часть r -> a
просто обобщается на f a
; исходные типы получаются с экземпляром Applicative
для ((->) r)
.
Как практический вопрос, pure
также позволяет вам писать аппликативные выражения более равномерным образом: pure f <*> effectful <*> pure x <*> effectful
в отличие от (\a b -> f a x b) <$> effectful <*> effectful
.