Как произносятся эти функции в классе типов Applicative:
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
(То есть, если бы они не были операторами, как бы их называть?)
В качестве примечания: если бы вы могли переименовать его pure
во что-нибудь более дружелюбное для нематематиков, как бы вы это назвали?
pure
может бытьmakeApplicative
.pure
предложение в качестве ответа, и я поддержу васОтветы:
Я думаю, что знание вашей математики здесь в значительной степени не имеет значения. Как вы, вероятно, знаете, Haskell заимствует несколько терминов из различных областей абстрактной математики, в первую очередь из теории категорий , откуда мы и получаем функторы и монады. Использование этих терминов в Haskell несколько отличается от формальных математических определений, но обычно они достаточно близки, чтобы в любом случае быть хорошими описательными терминами.
В
Applicative
типа находится где-то междуFunctor
иMonad
, поэтому можно было бы ожидать, что он имеет аналогичную математическую основу. Документация кControl.Applicative
модулю начинается с:Хм.
Monad
Думаю, не так запоминающе .В основном все это сводится к тому,
Applicative
что не соответствует ни одной особенно интересной концепции. математической точки зрения, поэтому нет никаких готовых терминов, которые отражали бы способ ее использования в Haskell. Итак, отложим пока математику.Если мы хотим знать, как позвонить
(<*>)
это может помочь узнать, что это в основном означает.Так в чем дело
Applicative
и почему? же мы называем это что?На
Applicative
практике получается способ поднять произвольные функции вFunctor
. Рассмотрим комбинациюMaybe
(возможно, самого простого нетривиальногоFunctor
) иBool
(аналогично простейшего нетривиального типа данных).Эта функция
fmap
позволяет нам перейтиnot
от работыBool
к работеMaybe Bool
. Но что, если мы хотим поднять(&&)
?Ну, это не то , что мы хотим , чтобы у всех ! Фактически, это бесполезно. Мы можем попытаться быть умным и украдкой другой
Bool
вMaybe
через спину ...... но это нехорошо. Во-первых, это неправильно. Во-вторых, это некрасиво . Мы могли бы продолжать попытки, но оказывается, что есть никакого способа поднять функцию с несколькими аргументами для работы с произвольным
Functor
. Раздражает!С другой стороны, мы могли бы сделать это легко , если бы мы использовали
Maybe
«sMonad
экземпляр:Теперь, это много хлопот просто перевести простую функцию - именно поэтому
Control.Monad
обеспечивает функцию , чтобы сделать это автоматически,liftM2
. Цифра 2 в названии указывает на то, что он работает с функциями ровно с двумя аргументами; аналогичные функции существуют для функций с 3, 4 и 5 аргументами. Эти функции лучше , но не идеальны, а указывать количество аргументов некрасиво и неуклюже.Это подводит нас к статье, в которой представлен класс типа Applicative. . В нем авторы делают по существу два наблюдения:
Functor
- это очень естественная вещь.Monad
Обычное функциональное приложение написано простым сопоставлением терминов, поэтому, чтобы сделать «поднятое приложение» как можно более простым и естественным, в документе представлены инфиксные операторы, заменяющие приложение, перенесенные в
Functor
класс, и класс типа, чтобы предоставить все необходимое для этого. .Все это подводит нас к следующему пункту:
(<*>)
просто представляет собой приложение функции - так зачем произносить его иначе, чем вы произносите пробельный «оператор сопоставления»?Но если это не очень удовлетворительно, мы можем заметить, что
Control.Monad
модуль также предоставляет функцию, которая делает то же самое для монад:Где
ap
, конечно, короткий для «применить». Поскольку любойMonad
может бытьApplicative
иap
нуждается только в подмножестве функций, присутствующих в последнем, мы, возможно, можем сказать, что если бы он(<*>)
не был оператором, его следовало бы вызватьap
.Мы также можем подойти к вещам с другой стороны. Операция
Functor
подъема вызывается,fmap
потому что это обобщениеmap
операции над списками. Какая функция в списках могла бы работать(<*>)
? Конечно, есть то, чтоap
есть в списках, но само по себе это не особенно полезно.На самом деле, списки могут интерпретироваться более естественно. Что приходит в голову, когда вы смотрите на следующую подпись типа?
Есть что-то настолько заманчивое в идее выстраивания списков параллельно, применяя каждую функцию в первом к соответствующему элементу второго. К несчастью для нашего старого друга
Monad
, эта простая операция нарушает законы монад, если списки имеют разную длину. Но он приносит штрафApplicative
, и в этом случае он(<*>)
становится способом объединения обобщенной версииzipWith
, так что, возможно, мы можем представить себе, как это называетсяfzipWith
?Эта идея застегивания на самом деле завершает круг. Помните ту математику о моноидальных функторах? Как следует из названия, это способ объединения структуры моноидов и функторов, оба из которых являются знакомыми классами типов Haskell:
Как бы они выглядели, если бы вы сложили их в коробку и немного встряхнули? Оттуда
Functor
мы сохраним идею структуры, независимой от ее параметра типа , а затемMonoid
сохраним общую форму функций:Мы не хотим предполагать, что есть способ создать действительно «пустой»
Functor
, и мы не можем вызвать значение произвольного типа, поэтому мы исправим типmfEmpty
asf ()
.Мы также не хотим, чтобы принудительно
mfAppend
требовался параметр согласованного типа, поэтому теперь у нас есть это:Для чего нужен тип результата
mfAppend
? У нас есть два произвольных типа, о которых мы ничего не знаем, поэтому у нас не так много вариантов. Самое разумное - просто сохранить оба:В этот момент
mfAppend
теперь ясно обобщенный вариантzip
в списках, и мы можем реконструироватьApplicative
легко:Это также показывает нам, что
pure
связано с элементом идентичности aMonoid
, поэтому другими хорошими именами для него может быть что угодно, предлагающее значение единицы, нулевую операцию или что-то подобное.Это было долго, так что резюмирую:
(<*>)
- это просто модифицированное приложение-функция, поэтому вы можете прочитать его как «ap» или «применить», или полностью исключить его, как и обычное приложение-функцию.(<*>)
также примерно обобщаетzipWith
списки, поэтому вы можете читать его как «zip-функторы с», аналогично чтениюfmap
«сопоставить функтор с».Первый ближе к замыслу
Applicative
класса типа - как следует из названия - так что я рекомендую.Фактически, я призываю к либеральному использованию, а не к произношению всех операторов поднятого приложения :
(<$>)
, который переводит функцию с одним аргументом вFunctor
(<*>)
, который связывает функцию с несколькими аргументами черезApplicative
(=<<)
, который связывает функцию, которая вводит вMonad
существующее вычислениеПо сути, все три являются обычным функциональным приложением, немного приправленным.
источник
Applicative
и функциональный идиоматический стиль, который он продвигает, не вызывают достаточной любви, поэтому я не мог устоять перед шансом немного превозносить его достоинства, чтобы объяснить, как я (не) произносю(<*>)
.Applicative
's! Что-то вроде[| f a b c d |]
(как предполагалось в исходной статье). Тогда нам не понадобится<*>
комбинатор, и вы должны ссылаться на такое выражение как на пример «применения функции в функциональном контексте»Monad
. ИлиFunctor
илиMonoid
что-нибудь еще, в котором есть устоявшийся термин, состоящий из менее чем трех прилагательных. «Аппликатив» - это просто скучное, хотя и достаточно информативное, название, наложенное на то, что скорее всего в нем нуждается.Поскольку у меня нет амбиций улучшить технический ответ CA McCann , я возьмусь за более пушистый:
В качестве альтернативы, особенно с учетом того, что нет конца постоянным воплям, наполненным тревогой и предательством, против
Monad
версии, называемой "return
", я предлагаю другое название, которое указывает на его функцию таким образом, чтобы удовлетворить самые императивные требования программистов. , и самый функциональный из ... ну, надеюсь, каждый может так же пожаловаться на:inject
.Примите значение. «Инъекция» это в
Functor
,Applicative
,Monad
или что-у-вы. Голосую за "inject
", и я одобрил это сообщение.источник
inject
- отличное имя и, вероятно, лучше, чем мое, хотя в качестве небольшого примечания, "inject" используется - я думаю - в Smalltalk и Ruby для какого-то метода левого свертывания. Я никогда не понимал этого выбора имени, хотя ...inject
в Ruby и Smalltalk, потому что это как будто вы «вставляете» оператор между каждым элементом в списке. По крайней мере, я всегда так думал об этом.foldr
. (Вы заменяете(:)
and[]
, где(:)
принимает 2 аргумента и[]
является константой, следовательно,foldr (+) 0 (1:2:3:[])
↝1+2+3+0
.) НаBool
нем простоif
-then
-else
(две константы, выберите одну), и потому чтоMaybe
он называетсяmaybe
… В Haskell нет единого имени / функции для этого, поскольку все они имеют разные типы (в общем, elim - это просто рекурсия / индукция)Вкратце:
<*>
вы можете назвать это применением . ТакMaybe f <*> Maybe a
можно произносить как « применитьMaybe f
над»Maybe a
.Вы можете переименовать
pure
вof
, как это делают многие библиотеки JavaScript. В JS вы можете создать файл сMaybe
расширениемMaybe.of(a)
.Также в вики Haskell есть страница о произношении языковых операторов здесь
источник
Источник: Программирование на Haskell из первых принципов , Крис Аллен и Джули Моронуки.
источник