¿Cómo se pronuncian estas funciones en la clase de tipos Applicative?
(<*>) :: f (a -> b) -> f a -> f b
(*>)  :: f a -> f b -> f b
(<*)  :: f a -> f b -> f a(Es decir, si no fueran operadores, ¿cómo se llamarían?)
Como nota al margen, si pudieras cambiar el nombre purea algo más amigable para los no matemáticos, ¿cómo lo llamarías?

purepodría sermakeApplicative.puresugerencia como respuesta y te votaréRespuestas:
Saber sus matemáticas, o no, es en gran parte irrelevante aquí, creo. Como probablemente sepa, Haskell toma prestados algunos fragmentos de terminología de varios campos de las matemáticas abstractas, sobre todo la teoría de categorías , de donde obtenemos functores y mónadas. El uso de estos términos en Haskell difiere un poco de las definiciones matemáticas formales, pero por lo general están lo suficientemente cerca como para ser buenos términos descriptivos de todos modos.
La
Applicativeclase de tipo se encuentra en algún lugar entreFunctoryMonad, por lo que uno esperaría que tuviera una base matemática similar. La documentación delControl.Applicativemódulo comienza con:Hmm.
No es tan pegadizo como
Monad, creo.Básicamente, todo esto se reduce a que
Applicativeno corresponde a ningún concepto que sea particularmente interesante matemáticamente, por lo que no hay términos prefabricados que capturen la forma en que se usa en Haskell. Por lo tanto, deje las matemáticas a un lado por ahora.Si queremos saber cómo llamarlo
(<*>), puede ser útil saber qué significa básicamente.Entonces, ¿qué pasa
Applicative, de todos modos, y por qué lo llamamos así?En la
Applicativepráctica, lo que equivale a una forma de convertir funciones arbitrarias en aFunctor. Considere la combinación deMaybe(posiblemente el tipo de datos no trivial más simpleFunctor) yBool(del mismo modo, el tipo de datos no trivial más simple).La función
fmapnos permite pasarnotde trabajarBoola trabajarMaybe Bool. ¿Pero y si queremos levantarnos(&&)?Bueno, ¡eso no es lo que queremos en absoluto ! De hecho, es bastante inútil. Podemos tratar de ser inteligentes y colarse otra
BoolenMaybepor la parte posterior ...... pero eso no es bueno. Por un lado, está mal. Por otra parte, es feo . Podríamos seguir intentándolo, pero resulta que no hay forma de levantar una función de múltiples argumentos para trabajar en un arbitrario
Functor. ¡Molesto!Por otro lado, podríamos hacerlo fácilmente si usamos
MaybelaMonadinstancia de:Ahora, traducir una función simple es muy complicado, por lo que
Control.Monadproporciona una función para hacerlo automáticamenteliftM2. El 2 en su nombre se refiere al hecho de que trabaja en funciones de exactamente dos argumentos; existen funciones similares para funciones de 3, 4 y 5 argumentos. Estas funciones son mejores , pero no perfectas, y especificar el número de argumentos es feo y torpe.Lo que nos lleva al artículo que introdujo la clase de tipo Aplicativo . En él, los autores hacen esencialmente dos observaciones:
Functores algo muy natural de hacerMonadLa aplicación de función normal se escribe mediante una simple yuxtaposición de términos, por lo que para hacer que la "aplicación elevada" sea lo más simple y natural posible, el artículo presenta operadores infijos para sustituir la aplicación, elevados en
Functory una clase de tipo para proporcionar lo que se necesita para eso. .Todo lo cual nos lleva al siguiente punto:
(<*>)simplemente representa la aplicación de la función, entonces, ¿por qué pronunciarla de manera diferente a como lo hace el "operador de yuxtaposición" de espacios en blanco?Pero si eso no es muy satisfactorio, podemos observar que el
Control.Monadmódulo también proporciona una función que hace lo mismo para las mónadas:Donde
apes, por supuesto, la abreviatura de "aplicar". Dado que cualquieraMonadpuede serApplicative, yapnecesita solo el subconjunto de características presentes en este último, quizás podamos decir que si(<*>)no fuera un operador, debería llamarseap.También podemos abordar las cosas desde la otra dirección. La
Functoroperación de elevación se llamafmapporque es una generalización de lamapoperación en listas. ¿Qué tipo de función en las listas funcionaría(<*>)? Hay lo queaphace en las listas, por supuesto, pero eso no es particularmente útil por sí solo.De hecho, existe una interpretación quizás más natural para las listas. ¿Qué le viene a la mente cuando mira la siguiente firma de tipo?
Hay algo tan tentador en la idea de alinear las listas en paralelo, aplicando cada función de la primera al elemento correspondiente de la segunda. Desafortunadamente para nuestro viejo amigo
Monad, esta simple operación viola las leyes de las mónadas si las listas tienen diferentes longitudes. Pero funciona bienApplicative, en cuyo caso se(<*>)convierte en una forma de encadenar una versión generalizada dezipWith, así que quizás podamos imaginarnos llamarlofzipWith.Esta idea de cremallera en realidad nos trae un círculo completo. ¿Recuerda lo anterior de las matemáticas, sobre los functores monoidales? Como su nombre indica, estas son una forma de combinar la estructura de monoides y functores, los cuales son clases de tipos familiares de Haskell:
¿Cómo se verían estos si los pones en una caja juntos y la agitas un poco? De
Functormantendremos la idea de una estructura independiente de su parámetro de tipo , y deMonoidmantendremos la forma general de las funciones:No queremos asumir que hay una manera de crear un verdadero "vacío"
Functor, y no podemos conjurar un valor de un tipo arbitrario, así que arreglaremos el tipo demfEmptycomof ().Tampoco queremos forzar la
mfAppendnecesidad de un parámetro de tipo consistente, así que ahora tenemos esto:¿Para qué es el tipo de resultado
mfAppend? Tenemos dos tipos arbitrarios de los que no sabemos nada, por lo que no tenemos muchas opciones. Lo más sensato es mantener ambos:En ese punto
mfAppendahora es claramente una versión generalizada dezipen listas, y podemos reconstruirApplicativefácilmente:Esto también nos muestra que
pureestá relacionado con el elemento de identidad de aMonoid, por lo que otros buenos nombres para él podrían ser cualquier cosa que sugiera un valor unitario, una operación nula o algo así.Eso fue largo, para resumir:
(<*>)es sólo una aplicación de función modificada, por lo que puede leerla como "ap" o "aplicar", o elírsela por completo como lo haría con una aplicación de función normal.(<*>)también generaliza de forma aproximadazipWithen listas, por lo que puede leerlo como "zipfmapfunctor con" , de manera similar a leer como "mapear un functor con".El primero está más cerca de la intención de la
Applicativeclase de tipo, como sugiere el nombre, así que eso es lo que recomiendo.De hecho, recomiendo el uso liberal y la no pronunciación de todos los operadores de aplicaciones levantados :
(<$>), que eleva una función de un solo argumento a unaFunctor(<*>), que encadena una función de múltiples argumentos a través de unaApplicative(=<<), que une una función que ingresa aMonaden un cálculo existenteLos tres son, en el fondo, solo una aplicación de función normal, un poco condimentada.
fuente
Applicativey el estilo idiomático funcional que promueve no reciben suficiente amor, así que no pude resistir la oportunidad de ensalzar un poco sus virtudes como un medio para explicar cómo (no) pronuncio(<*>).Applicative's! Algo parecido[| f a b c d |](como sugiere el artículo original). Entonces no necesitaríamos el<*>combinador y se referiría a dicha expresión como un ejemplo de "aplicación de función en un contexto functorial"Monad. OFunctoroMonoidcualquier otra cosa que tenga un término bien establecido que involucre menos de tres adjetivos. "Aplicativo" es simplemente un nombre poco inspirador, aunque razonablemente descriptivo, colocado en algo que más bien lo necesitaba.Como no tengo la ambición de mejorar la respuesta técnica de CA McCann , abordaré la más esponjosa:
Como alternativa, especialmente porque no hay fin al constante llanto lleno de angustia y traición contra la
Monadversión, llamada "return", propongo otro nombre, que sugiere su función de una manera que puede satisfacer el más imperativo de los programadores imperativos. , y el más funcional de ... bueno, es de esperar, todo el mundo puede quejarse sobre la misma:inject.Toma un valor. "Inyectar" en el
Functor,Applicative,Monad, o lo que usted quiera. Voto por "inject" y aprobé este mensaje.fuente
injectes un nombre excelente y probablemente mejor que el mío, aunque como nota al margen menor, "inyectar" se usa en, creo, Smalltalk y Ruby para un método de plegado a la izquierda de algún tipo. Sin embargo, nunca entendí esa elección de nombre ...injecten Ruby y Smalltalk se usa porque es como si estuvieras "inyectando" un operador entre cada elemento de la lista. Al menos, así siempre lo pensé.foldr. (Reemplaza(:)y[], donde(:)toma 2 argumentos y[]es una constante, porfoldr (+) 0 (1:2:3:[])lo tanto ↝1+2+3+0.) EnBooles soloif-then-else(dos constantes, elija una) y paraMaybeque se llamemaybe... Haskell no tiene un solo nombre / función para esto, ya que todos tienen diferentes tipos (en general, la eliminación es solo recursión / inducción)En breve:
<*>puede llamarlo aplicar . Por lo queMaybe f <*> Maybe ase puede pronunciar como aplicarMaybe fsobreMaybe a.Puede cambiar el nombre
pureaof, como hacen muchas bibliotecas de JavaScript. En JS puede crear un archivoMaybeconMaybe.of(a).Además, la wiki de Haskell tiene una página sobre la pronunciación de los operadores de idiomas aquí.
fuente
Fuente: Programación de Haskell de First Principles , por Chris Allen y Julie Moronuki
fuente