Comment prononcez-vous ces fonctions dans la classe de types Applicative:
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
(Autrement dit, s'ils n'étaient pas des opérateurs, comment pourraient-ils être appelés?)
En pure
passant , si vous pouviez renommer quelque chose de plus convivial pour les non-mathématiciens, comment l'appelleriez-vous?
pure
pourrait êtremakeApplicative
.pure
suggestion comme réponse et je vous donnerai un vote favorableRéponses:
Connaître vos maths, ou non, est largement hors de propos ici, je pense. Comme vous le savez probablement, Haskell emprunte quelques bouts de terminologie à divers domaines des mathématiques abstraites, notamment la théorie des catégories , d'où nous obtenons des foncteurs et des monades. L'utilisation de ces termes dans Haskell diverge quelque peu des définitions mathématiques formelles, mais ils sont généralement assez proches pour être de toute façon de bons termes descriptifs.
La
Applicative
classe de types se situe quelque part entreFunctor
etMonad
, on s'attend donc à ce qu'elle ait une base mathématique similaire. La documentation duControl.Applicative
module commence par:Hmm.
Pas aussi accrocheur que
Monad
je pense.Ce à quoi tout cela se résume fondamentalement, c'est que
Applicative
cela ne correspond à aucun concept particulièrement intéressant mathématiquement, donc il n'y a pas de termes prêts à l'emploi qui traînent qui capturent la façon dont il est utilisé dans Haskell. Alors, mettez les calculs de côté pour le moment.Si nous voulons savoir comment appeler,
(<*>)
il peut être utile de savoir ce que cela signifie fondamentalement.Alors , quel est avec
Applicative
, de toute façon, et pourquoi ne nous l' appelons ça?Ce qui
Applicative
revient en pratique est un moyen de soulever des fonctions arbitraires en aFunctor
. Considérez la combinaison deMaybe
(sans doute le plus simple non trivialFunctor
) etBool
(de même le type de données non trivial le plus simple).La fonction
fmap
nous permet de passernot
du travailBool
au travailMaybe Bool
. Mais que faire si nous voulons soulever(&&)
?Eh bien, ce n'est pas ce que nous voulons du tout ! En fait, c'est à peu près inutile. Nous pouvons essayer d'être intelligents et
Bool
en introduire un autreMaybe
par l'arrière ...... mais ce n'est pas bon. D'une part, c'est faux. Pour autre chose, c'est moche . Nous pourrions continuer d'essayer, mais il s'avère qu'il n'y a aucun moyen de lever une fonction d'arguments multiples pour travailler sur un arbitraire
Functor
. Énervant!D'un autre côté, nous pourrions le faire facilement si nous
Maybe
utilisions l'Monad
instance de:Maintenant, c'est beaucoup de tracas juste pour traduire une fonction simple - ce qui est la raison pour laquelle
Control.Monad
fournit une fonction pour le faire automatiquement,liftM2
. Le 2 dans son nom fait référence au fait qu'il fonctionne sur des fonctions d'exactement deux arguments; des fonctions similaires existent pour les fonctions d'argument 3, 4 et 5. Ces fonctions sont meilleures , mais pas parfaites, et spécifier le nombre d'arguments est laid et maladroit.Ce qui nous amène à l' article qui a introduit la classe de type Applicatif . Les auteurs y font essentiellement deux observations:
Functor
est une chose très naturelle à faireMonad
L'application de fonction normale est écrite par une simple juxtaposition de termes, donc pour rendre «l'application soulevée» aussi simple et naturelle que possible, l'article présente des opérateurs infixes pour remplacer l'application, soulevés dans le
Functor
, et une classe de type pour fournir ce qui est nécessaire pour cela .Tout cela nous amène au point suivant:
(<*>)
représente simplement une application de fonction - alors pourquoi la prononcer différemment de celle de l '«opérateur de juxtaposition» d'espaces blancs?Mais si ce n'est pas très satisfaisant, on peut observer que le
Control.Monad
module fournit également une fonction qui fait la même chose pour les monades:Où
ap
est, bien sûr, l'abréviation de «appliquer». Puisque toutMonad
peut êtreApplicative
, etap
n'a besoin que du sous-ensemble de fonctionnalités présentes dans ce dernier, nous pouvons peut-être dire que si ce(<*>)
n'était pas un opérateur, il devrait être appeléap
.On peut aussi aborder les choses dans l'autre sens. L'
Functor
opération de levage est appeléefmap
car c'est une généralisation de l'map
opération sur les listes. Quel genre de fonction sur les listes fonctionnerait-il(<*>)
? Il y a ce quiap
fait sur les listes, bien sûr, mais ce n'est pas particulièrement utile en soi.En fait, il existe une interprétation peut-être plus naturelle des listes. Qu'est-ce qui vous vient à l'esprit lorsque vous regardez la signature de type suivante?
Il y a quelque chose de tellement tentant dans l'idée d'aligner les listes en parallèle, en appliquant chaque fonction de la première à l'élément correspondant de la seconde. Malheureusement pour notre vieil ami
Monad
, cette opération simple viole les lois de la monade si les listes sont de longueurs différentes. Mais cela fait une amendeApplicative
, auquel cas(<*>)
devient une façon d' enchaîner une version généralisée dezipWith
, alors peut-être pouvons-nous imaginer l'appelerfzipWith
?Cette idée de fermeture éclair nous amène en fait à boucler la boucle. Rappelez-vous ce truc de maths plus tôt, à propos des foncteurs monoïdaux? Comme son nom l'indique, il s'agit d'un moyen de combiner la structure des monoïdes et des foncteurs, qui sont tous deux des classes de type Haskell familières:
À quoi ressembleraient-ils si vous les mettiez ensemble dans une boîte et la secouiez un peu? De
Functor
nous allons garder l'idée d'une structure indépendante de son paramètre de type , et deMonoid
nous garderons la forme globale des fonctions:Nous ne voulons pas supposer qu'il existe un moyen de créer un vraiment "vide"
Functor
, et nous ne pouvons pas évoquer une valeur d'un type arbitraire, nous allons donc corriger le type demfEmpty
asf ()
.Nous ne voulons pas non plus forcer
mfAppend
le besoin d'un paramètre de type cohérent, alors maintenant nous avons ceci:À quoi sert le type de résultat
mfAppend
? Nous avons deux types arbitraires dont nous ne savons rien, donc nous n'avons pas beaucoup d'options. Le plus judicieux est de garder les deux:À quel point
mfAppend
est maintenant clairement une version généralisée dezip
on lists, et nous pouvons reconstruireApplicative
facilement:Cela nous montre également qu'il
pure
est lié à l'élément d'identité de aMonoid
, donc d'autres bons noms peuvent être tout ce qui suggère une valeur unitaire, une opération nulle ou autre.C'était long, donc pour résumer:
(<*>)
est juste une application de fonction modifiée, vous pouvez donc soit la lire comme "ap" ou "appliquer", soit l'éliminer entièrement comme vous le feriez pour une application de fonction normale.(<*>)
généralise aussi grossièrementzipWith
sur les listes, de sorte que vous pouvez le lire en tant que "foncteurs zip avec", de la même manièrefmap
que "mapper un foncteur avec".Le premier est plus proche de l'intention de la
Applicative
classe de type - comme son nom l'indique - c'est donc ce que je recommande.En fait, j'encourage l'utilisation libérale, et la non-prononciation, de tous les opérateurs d'application levés :
(<$>)
, qui lève une fonction à un seul argument en unFunctor
(<*>)
, qui enchaîne une fonction multi-arguments via unApplicative
(=<<)
, qui lie une fonction qui entre unMonad
sur un calcul existantTous les trois sont, au fond, juste une application de fonction régulière, un peu épicée.
la source
Applicative
et le style idiomatique fonctionnel qu'il promeut ne suscite pas assez d'amour, donc je n'ai pas pu résister à la chance de vanter un peu ses vertus comme un moyen d'expliquer comment je (ne) prononce pas(<*>)
.Applicative
's! Quelque chose comme[| f a b c d |]
(comme suggéré par le papier original). Ensuite, nous n'aurions pas besoin du<*>
combinateur et vous feriez référence à une telle expression comme un exemple d '"application de fonction dans un contexte fonctionnel"Monad
. OuFunctor
ouMonoid
ou toute autre chose qui a un terme bien établi comportant moins de trois adjectifs. «Applicatif» est simplement un nom sans intérêt, quoique raisonnablement descriptif, appliqué à quelque chose qui en avait plutôt besoin.Comme je n'ai aucune ambition d'améliorer la réponse technique de CA McCann , je vais aborder la plus pelucheuse:
Comme alternative, d'autant plus qu'il n'y a pas de fin à l'angoisse et à la trahison constantes criées contre la
Monad
version, appelée "return
", je propose un autre nom, qui suggère sa fonction d'une manière qui peut satisfaire le plus impératif des programmeurs impératifs et le plus fonctionnel de ... eh bien, je l' espère, tout le monde peut se plaindre de la même chose:inject
.Prenez une valeur. « Injecter » dans le
Functor
,Applicative
,Monad
ou ce que vous voudrez. Je vote pour "inject
" et j'ai approuvé ce message.la source
inject
est un excellent nom et probablement meilleur que le mien, bien que comme note secondaire mineure, "inject" est utilisé dans - je pense - Smalltalk et Ruby pour une méthode de pliage à gauche. Je n'ai jamais compris ce choix de nom, cependant ...inject
dans Ruby & Smalltalk est utilisé parce que c'est comme si vous "injectiez" un opérateur entre chaque élément de la liste. Du moins, c'est comme ça que j'y ai toujours pensé.foldr
. (Vous remplacez(:)
et[]
, où(:)
prend 2 arguments et[]
est une constante, d'oùfoldr (+) 0 (1:2:3:[])
↝1+2+3+0
.) SurBool
c'est justeif
-then
-else
(deux constantes, choisissez-en une) et pourMaybe
ça s'appellemaybe
... Haskell n'a pas de nom / fonction unique pour cela, car tous ont des types différents (en général elim n'est que récursion / induction)En bref:
<*>
vous pouvez l'appeler appliquer . Donc,Maybe f <*> Maybe a
peut être prononcé comme appliquéMaybe f
surMaybe a
.Vous pouvez renommer
pure
enof
, comme le font de nombreuses bibliothèques JavaScript. Dans JS, vous pouvez créer unMaybe
avecMaybe.of(a)
.En outre, le wiki de Haskell a une page sur la prononciation des opérateurs de langue ici
la source
Source: Programmation Haskell à partir des premiers principes , par Chris Allen et Julie Moronuki
la source