No me interesa la primera definición; esas no me ayudarían a escribir un programa real (+1 si me convences de que estoy equivocado). Ayúdame a comprender la segunda definición. Creo que mapear, filtrar y reducir son útiles: me permiten programar en un nivel superior: menos errores, código más corto y claro.
Las dos definiciones son básicamente lo mismo. El primero se basa en la definición formal y los ejemplos que da son combinadores primitivos , los bloques de construcción más pequeños posibles. Pueden ayudarlo a escribir un programa real en la medida en que, con ellos, puede construir combinadores más sofisticados. Piense en combinadores como S y K como el lenguaje de máquina de una hipotética "computadora combinatoria". Las computadoras reales no funcionan de esa manera, por supuesto, por lo que en la práctica, por lo general, las operaciones de nivel superior se implementarán detrás de escena de otras maneras, pero la base conceptual sigue siendo una herramienta útil para comprender el significado de esas operaciones de nivel superior. operaciones.
La segunda definición que da es más informal y sobre el uso de combinadores más sofisticados, en forma de funciones de orden superior que combinan otras funciones de varias formas. Tenga en cuenta que si los bloques de construcción básicos son los combinadores primitivos anteriores, todo lo que se construye a partir de ellos es una función de orden superior y también un combinador. Sin embargo, en un lenguaje donde existen otras primitivas, hay una distinción entre cosas que son o no funciones, en cuyo caso un combinador se define típicamente como una función que manipula otras funciones de una manera general, en lugar de operar en cualquier no funcionan las cosas directamente.
¿Cuáles son más ejemplos de combinadores como mapa, filtro?
¡Demasiados para enumerarlos! Ambos transforman una función que describe el comportamiento de un solo valor en una función que describe el comportamiento de una colección completa. También puede tener funciones que solo transformen otras funciones, como componerlas de un extremo a otro o dividir y recombinar argumentos. Puede tener combinadores que conviertan las operaciones de un solo paso en operaciones recursivas que produzcan o consuman colecciones. O todo tipo de otras cosas, de verdad.
¿Qué combinadores implementan a menudo los lenguajes de programación?
Eso va a variar bastante. Hay relativamente pocos combinadores completamente genéricos, en su mayoría los primitivos mencionados anteriormente, por lo que en la mayoría de los casos, los combinadores tendrán algún conocimiento de las estructuras de datos que se estén utilizando (incluso si esas estructuras de datos se construyen a partir de otros combinadores de todos modos), en las que En el caso de que haya típicamente un puñado de combinadores "totalmente genéricos" y luego cualquier forma especializada que alguien haya decidido proporcionar. Hay una cantidad ridícula de casos en los que (versiones adecuadamente generalizadas de) mapear, plegar y desplegar son suficientes para hacer casi todo lo que pueda desear.
¿Cómo pueden ayudarme los combinadores a diseñar una mejor API?
Exactamente como dijiste, pensando en términos de operaciones de alto nivel y la forma en que interactúan, en lugar de detalles de bajo nivel.
Piense en la popularidad de los bucles de estilo "para cada" sobre las colecciones, que le permiten abstraer los detalles de enumerar una colección. Estas son solo operaciones de mapeo / plegado en la mayoría de los casos, y al convertirlo en un combinador (en lugar de sintaxis incorporada) puede hacer cosas como tomar dos bucles existentes y combinarlos directamente de varias maneras: anidar uno dentro del otro, hacer uno tras otro, y así sucesivamente, simplemente aplicando un combinador, en lugar de hacer malabares con un montón de código.
¿Cómo diseño combinadores eficaces?
Primero, piense en qué operaciones tienen sentido en los datos que utiliza su programa. Luego, piense en cómo esas operaciones se pueden combinar de manera significativa de manera genérica, así como en cómo las operaciones se pueden dividir en partes más pequeñas que se vuelven a conectar entre sí. Lo principal es trabajar con transformaciones y operaciones , no acciones directas . Cuando tiene una función que simplemente hace alguna funcionalidad complicada de una manera opaca y solo escupe algún tipo de resultado predigerido, no hay mucho que pueda hacer con eso. Deje los resultados finales en manos del código que usa los combinadores: desea cosas que lo lleven del punto A al punto B, no cosas que esperan ser el comienzo o el final de un proceso.
¿A qué se parecen los combinadores en un lenguaje no funcional (digamos, Java), o qué utilizan estos lenguajes en lugar de los combinadores?
Ahahahaha. Es curioso que pregunte, porque los objetos son cosas de orden superior en primer lugar: tienen algunos datos, pero también llevan un montón de operaciones, y mucho de lo que constituye un buen diseño de POO se reduce a "los objetos deberían normalmente actúan como combinadores, no como estructuras de datos ".
Entonces, probablemente la mejor respuesta aquí es que, en lugar de cosas similares a un combinador, usan clases con muchos métodos getter y setter o campos públicos, y una lógica que consiste principalmente en realizar una acción opaca y predefinida.