¿La programación funcional aumenta la "brecha representacional" entre problemas y soluciones? [cerrado]

18

Dado que el lenguaje de máquina (p. Ej. 0110101000110101), Los lenguajes de computadora generalmente han evolucionado hacia formas más altas de abstracción, lo que facilita la comprensión del código cuando se aplica a un problema. Assembler era una abstracción sobre el código de máquina, C era una abstracción sobre el ensamblador, etc.

El diseño orientado a objetos parece ser muy bueno para permitirnos modelar un problema en términos de objetos, por ejemplo, el problema de un sistema de registro de cursos universitarios puede modelarse con una Courseclase, una Studentclase, etc. Luego, cuando escribimos la solución en un lenguaje OO, tenemos clases similares que tienen responsabilidades y que generalmente son útiles para el diseño, especialmente para modularizar el código. Si le doy este problema a 10 equipos independientes que lo resuelven con un método OO, generalmente las 10 soluciones tendrán en común las clases relacionadas con el problema. Puede haber muchas diferencias cuando comienzas a entrar en el acoplamiento y las interacciones de esas clases, por lo que no existe el "vacío de representación cero".

Mi experiencia con la programación funcional es muy limitada (sin uso en el mundo real, solo programas de tipo Hello World). No puedo ver cómo dichos lenguajes permiten asignar fácilmente soluciones FP a problemas (con una brecha de representación baja) como lo hacen los lenguajes OO.

Entiendo las ventajas de FP con respecto a la programación concurrente. ¿Pero me estoy perdiendo algo, o FP no se trata de reducir una brecha de representación (hacer que las soluciones sean más fáciles de entender)?

Otra forma de preguntar esto: ¿el código FP de 10 equipos diferentes que resuelven el mismo problema del mundo real tiene mucho en común?


De Wikipedia en Abstracción (informática) (énfasis mío):

Los lenguajes de programación funcional exhiben comúnmente abstracciones relacionadas con funciones , tales como abstracciones lambda (convertir un término en una función de alguna variable), funciones de orden superior (los parámetros son funciones), abstracción de corchetes (convertir un término en una función de una variable).

La brecha representacional podría aumentar potencialmente, porque [algunos] problemas del mundo real no se modelan fácilmente con tales abstracciones.


Otra forma en que veo una disminución de la brecha representacional es en el rastreo de los elementos de la solución hasta el problema. Los 0'sys 1en el código de máquina son muy difíciles de rastrear, mientras que la Studentclase es fácil de rastrear. No todas las clases de OO se remontan fácilmente al espacio del problema, pero muchas lo hacen.

¿Las abstracciones de FP no siempre necesitan explicarse para descubrir qué parte del espacio del problema están resolviendo (aparte de los problemas de matemáticas )?OK, estoy bien en esta parte. Después de ver muchos más ejemplos, veo cómo las abstracciones de FP son muy claras para las partes del problema que se expresan en el procesamiento de datos.


La respuesta aceptada a una pregunta relacionada ¿ Se puede usar UML para modelar un programa funcional? - dice "Los programadores funcionales no tienen mucho uso para los diagramas". Realmente no me importa si es UML, pero me hace preguntarme si las abstracciones de FP son fáciles de entender / comunicar, si no hay diagramas que se utilicen ampliamente (suponiendo que esta respuesta sea correcta). Una vez más, mi nivel de uso / comprensión de FP es trivial, por lo que entiendo que no hay necesidad de diagramas en programas simples de FP.

El diseño OO tiene niveles de abstracción de función / clase / paquete, con encapsulación (control de acceso, ocultación de información) en cada uno, lo que facilita la gestión de la complejidad. Estos son elementos que permiten pasar del problema a la solución y viceversa.


Muchas respuestas hablan de cómo se realizan el análisis y el diseño en FP de una manera análoga a OO, pero hasta ahora nadie cita nada de alto nivel (Paul citó algunas cosas interesantes, pero es de bajo nivel). Ayer busqué mucho en Google y encontré una discusión interesante. Lo siguiente es de Refactoring Functional Programs de Simon Thompson (2004) (énfasis mío)

Al diseñar un sistema orientado a objetos, se da por sentado que el diseño precederá a la programación. Los diseños se escribirán utilizando un sistema como UML que es compatible con herramientas como Eclipse. Los programadores principiantes pueden aprender un enfoque de diseño visual utilizando sistemas como BlueJ. El trabajo sobre una metodología similar para la programación funcional se informa en FAD: Análisis funcional y diseño , pero existe muy poco trabajo. Puede haber varias razones para esto.

  • Los programas funcionales existentes son de una escala que no requiere diseño. Muchos programas funcionales son pequeños, pero otros, como el Glasgow Haskell Compiler, son sustanciales.

  • Los programas funcionales modelan directamente el dominio de la aplicación, lo que hace que el diseño sea irrelevante. Si bien los lenguajes funcionales proporcionan una variedad de abstracciones poderosas, es difícil argumentar que proporcionan todas y solo las abstracciones necesarias para modelar el mundo real.

  • Los programas funcionales se construyen como una serie de prototipos en evolución.

En la tesis de doctorado citada anteriormente , los beneficios del uso de metodologías de análisis y diseño (ADM) se describen independientemente de los paradigmas. Pero se argumenta que los ADM deben alinearse con el paradigma de implementación. Es decir, OOADM funciona mejor para la programación OO y no se aplica bien a otro paradigma como FP. Aquí hay una gran cita que creo que parafrasea lo que llamo brecha representacional:

se puede discutir extensamente sobre qué paradigma proporciona el mejor soporte para el desarrollo de software, pero se logra el paquete de desarrollo más natural, eficiente y efectivo cuando uno permanece dentro de un solo paradigma desde la descripción del problema hasta la implementación y entrega.

Aquí está el conjunto de diagramas propuestos por FAD:

  • diagramas de dependencia de funciones que presentan una función con aquellos que usa en su implementación;
  • diagrama de dependencia de tipo que proporciona el mismo servicio para tipos; y,
  • diagramas de dependencia del módulo que presentan vistas de la arquitectura del módulo del sistema.

Hay un estudio de caso en la sección 5.1 de la tesis del FAD, que es un sistema para automatizar la producción de datos relacionados con una liga de fútbol (soccer). Los requisitos son 100% funcionales, por ejemplo, ingresar resultados de fútbol, ​​producir tablas de la liga, tablas de puntaje, tablas de asistencia, transferir jugadores entre equipos, actualizar datos después de nuevos resultados, etc. No se menciona ninguna mención de cómo funciona FAD para resolver requisitos no funcionales , además de afirmar que "se debería permitir una nueva funcionalidad a un costo mínimo", algo que es casi imposible de probar.

Lamentablemente, aparte de FAD, no veo ninguna referencia moderna para los lenguajes de modelado (visual) que se proponen para FP. UML es otro paradigma, por lo que debemos olvidarlo.

Fuhrmanator
fuente
1
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
maple_shaft

Respuestas:

20

Los datos básicos están estructurados de la misma manera en casi cualquier paradigma. Tendrás a Student, a Course, etc., ya sea un objeto, una estructura, un registro o lo que sea. La diferencia con OOP no es cómo se estructuran los datos, sino cómo se estructuran las funciones.

De hecho, encuentro que los programas funcionales se ajustan mucho más a cómo pienso en un problema. Por ejemplo, para planificar el horario de un estudiante para el próximo semestre, piense en cosas como listas de cursos que un estudiante ha completado, cursos en un programa de grado de estudiante, cursos ofrecidos este semestre, cursos para los que un estudiante ha completado requisitos previos, cursos con tiempos que no No conflicto, etc.

De repente, no está tan claro qué clase debería crear y almacenar todas estas listas. Aún menos cuando tienes combinaciones complejas de estas listas. Sin embargo, debes elegir una clase.

En FP, escribe funciones que toman un alumno y una lista de cursos y devuelve una lista filtrada de cursos. Puede agrupar todas esas funciones en un módulo. No tiene que emparejarlo con una clase u otra.

Entonces, sus modelos de datos terminan pareciéndose más a cómo los programadores de OOP piensan en sus modelos, antes de que se contaminen con clases que no tienen otro propósito que proporcionar lugares convenientes para colocar funciones que operan en combinaciones de otras clases. No hay CourseStudentFilterListclases extrañas o similares que siempre termines necesitando en OOP, pero nunca pienses en el diseño inicial.

Karl Bielefeldt
fuente
55
@BenAaronson, el problema en mi experiencia es que cualquier función relacionada con un alumno se agrega a la clase de Alumno y sus responsabilidades crecen y crecen hasta que necesite presentarse StudentCourseFiltererpara mantener las cosas manejables
AlexFoxGill
3
Los enfoques de @Den Hybrid tienen sus méritos. Sin embargo, no es cierto que la distinción sea artificial. Scala tuvo que hacer muchos compromisos para adaptarse a OOP y FP (la inferencia de tipos menos poderosa es una. La complejidad es otra: sí, un lenguaje que combina OOP y FP tiende a ser más complejo , como en "difícil de usar" y entender "- que uno de sus hermanos más puros en los dos extremos).
Andres F.
3
@Den Véase también "La programación 'Mayormente funcional' de Erik Meijer no funciona" , que argumenta en contra del enfoque híbrido y de ir a la FP "fundamentalista".
Andres F.
44
@Den La popularidad que describe es, me temo, un accidente de la historia. Uso Scala en el trabajo, y es una bestia compleja debido a la forma en que intenta mezclar FP y OOP. Cambiar a un verdadero lenguaje FP como Haskell se siente como un soplo de aire fresco, ¡y tampoco estoy hablando desde una perspectiva académica!
Andres F.
3
@Den No puedo decir qué hacen esas funciones. Sin embargo, puedo decirle que si la primera función en FP fue una clasificación o un filtro, se llamaría filtro o clasificación , no func(tal como lo nombró IFilter, etc.). En general, en FP que le nombra funco fcuando cualquiera sorto filteres una opción válida! Por ejemplo, al escribir una función de orden superior que toma funccomo parámetro.
Andres F.
10

Cuando tomé mi clase de Java hace años, se esperaba que mostraramos nuestras soluciones a toda la clase, así que pude ver cómo piensa la gente; cómo resuelven los problemas lógicamente. Esperaba que las soluciones se agruparan en torno a tres o cuatro soluciones comunes. En cambio, vi como 30 estudiantes resolvieron el problema de 30 maneras completamente diferentes.

Naturalmente, a medida que los programadores novatos adquieran experiencia, obtendrán exposición a patrones de software comunes, comenzarán a usar esos patrones en su código y luego sus soluciones pueden fusionarse en torno a algunas estrategias óptimas. Estos patrones forman un lenguaje técnico mediante el cual los desarrolladores experimentados pueden comunicarse.

El lenguaje técnico que sustenta la programación funcional es la matemática . En consecuencia, los problemas que son más adecuados para resolver utilizando la programación funcional son esencialmente problemas matemáticos. Por matemática, no me estoy refiriendo al tipo de matemática que verías en soluciones de negocios, como sumas y restas. Más bien, estoy hablando del tipo de matemática que podrías ver en Math Overflow, o del tipo de matemática que verías en el motor de búsqueda de Orbitz (está escrito en Lisp).

Esta orientación tiene algunas ramificaciones importantes para los programadores funcionales que intentan resolver problemas de programación del mundo real:

  1. La programación funcional es más declarativa que imperativa; se ocupa principalmente de decirle a la computadora qué hacer, no cómo hacerlo.

  2. Los programas orientados a objetos a menudo se crean de arriba hacia abajo. Se crea un diseño de clase y se completan los detalles. Los programas funcionales a menudo se crean de abajo hacia arriba, comenzando con funciones pequeñas y detalladas que se combinan en funciones de nivel superior.

  3. La programación funcional puede tener ventajas para la creación de prototipos de lógica compleja, la construcción de programas flexibles que pueden cambiar y evolucionar orgánicamente, y la creación de software donde el diseño inicial no está claro.

  4. Los programas orientados a objetos pueden ser más adecuados para dominios de negocios porque las clases, los mensajes entre objetos y los patrones de software proporcionan una estructura que se asigna al dominio de negocios, captura su inteligencia de negocios y lo documenta.

  5. Debido a que todo el software práctico produce efectos secundarios (E / S), los lenguajes de programación puramente funcionales requieren un mecanismo para producir esos efectos secundarios mientras permanecen matemáticamente puros (mónadas).

  6. Los programas funcionales se pueden probar más fácilmente, debido a su naturaleza matemática. El sistema de tipos de Haskell puede encontrar cosas en tiempo de compilación que la mayoría de los lenguajes OO no pueden encontrar.

Y así. Al igual que con muchas cosas en informática, los lenguajes orientados a objetos y los lenguajes funcionales tienen diferentes compensaciones.

Algunos lenguajes OO modernos han adoptado algunos de los conceptos útiles de programación funcional, para que pueda tener lo mejor de ambos mundos. Linq, y las características del lenguaje que se agregaron para admitirlo, es un buen ejemplo de eso.

Robert Harvey
fuente
66
@thepacker: Tienes estado en la programación funcional. Solo la representación es diferente: en OOP usa variables mutables, mientras que en la programación funcional puede usar flujos infinitos de estados que se crean sobre la marcha cuando el programa necesita inspeccionarlos. Desafortunadamente, el estado a menudo se identifica con variables mutables, como si las variables mutables fueran la única forma de representar el estado. Como consecuencia, muchos creen que un lenguaje de programación sin variables mutables no puede modelar el estado.
Giorgio
12
"En consecuencia, los problemas que son más adecuados para resolver utilizando la programación funcional son esencialmente problemas matemáticos": no estoy de acuerdo con esta afirmación (ver también mi comentario anterior), al menos no veo por qué debería ser cierto o qué en realidad significa Puede ver atravesar una estructura de directorios como un problema matemático e implementarlo con una función recursiva, pero como el cliente no ve el código fuente, solo está resolviendo un problema práctico como encontrar un archivo en algún lugar del sistema de archivos. Encuentro que esa distinción entre problemas matemáticos y no matemáticos es artificial.
Giorgio
55
+1, pero no estoy vendido en los puntos 2 y 4. He visto muchos tutoriales y publicaciones de blog de Haskell que comienzan abordando un problema de arriba hacia abajo, definiendo todos los tipos y operaciones para ver cómo encaja todo mientras dejando cada valor y definición de función sin definir (bueno, definido para lanzar una excepción). Me parece que los programadores de Haskell tienden a modelar el problema más a fondo porque están más inclinados a agregar tipos triviales por el bien de la semántica, por ejemplo, agregar un SafeStringtipo para representar cadenas que se han escapado de HTML, y en general mantener un mayor seguimiento de efectos
Doval
44
"Los problemas que son más adecuados para resolver utilizando la programación funcional son esencialmente problemas matemáticos". Eso simplemente no es cierto. El hecho de que el concepto de mónadas provenga de la teoría de categorías tampoco significa que las tareas matemáticas sean el dominio más natural / adecuado para los lenguajes funcionales. Todo lo que significa es que el código escrito en lenguajes funcionales fuertemente tipados se puede describir, analizar y razonar sobre el uso de las matemáticas. Esta es una característica adicional poderosa, no algo que te impide escribir "Barbie Horse Adventures" en Haskell.
itsbruce
66
@itsbruce Barbie Horse Adventures es una simulación matemática seria del más alto calibre, es pidgeon agujereando FP en proyecciones numéricas demasiado complejas como matrices que describen el brillo físico del cabello de Barbie durante un período discreto en una variedad de posibles entornos del mundo real que convence a las personas a Deséchelo por completo como irrelevante para su codificación de problemas comerciales cotidianos.
Jimmy Hoffa
7

Me gustaría enfatizar un aspecto que encuentro importante y que no se ha cubierto en las otras respuestas.

En primer lugar, creo que la brecha de representación entre problemas y soluciones puede estar más en la mente del programador, de acuerdo con sus antecedentes y con los conceptos con los que están más familiarizados.

OOP y FP analizan los datos y las operaciones desde dos perspectivas diferentes y proporcionan diferentes compensaciones, como Robert Harvey ya ha señalado.

Un aspecto importante en el que difieren es la forma en que permiten ampliar su software.

Considere la situación en la que tiene una colección de tipos de datos y una colección de operaciones, por ejemplo, tiene diferentes formatos de imagen y mantiene una biblioteca de algoritmos para procesar imágenes.

La programación funcional hace que sea más fácil agregar nuevas operaciones a su software: solo necesita un cambio local en su código, es decir, agrega una nueva función, que maneja diferentes formatos de datos de entrada. Por otro lado, agregar nuevos formatos está más involucrado: necesita cambiar todas las funciones que ya ha implementado (cambio no local).

El enfoque orientado a objetos es simétrico a esto: cada tipo de datos lleva su propia implementación de todas las operaciones y es responsable de elegir la implementación correcta en tiempo de ejecución (despacho dinámico). Esto facilita agregar un nuevo tipo de datos (por ejemplo, un nuevo formato de imagen): simplemente agrega una nueva clase e implementa todos sus métodos. Por otro lado, agregar una nueva operación significa cambiar todas las clases que necesitan proporcionar esa operación. En muchos idiomas, esto se hace extendiendo una interfaz y adaptando todas las clases que la implementan.

Este enfoque diferente de la extensión es una de las razones por las cuales la OOP es más apropiada para ciertos problemas en los que el conjunto de operaciones varía con menos frecuencia que el conjunto de tipos de datos en los que funcionan estas operaciones. Un ejemplo típico son interfaces gráficas de usuario: usted tiene un conjunto fijo de operaciones que todos los controles deben implementar ( paint, resize, move, etc.) y una colección de widgets que desea extender.

Entonces, de acuerdo con esta dimensión, OOP y FP son solo dos formas especulares de organizar su código. Ver SICP , en particular la Sección 2.4.3, Tabla 2.22, y el párrafo Mensaje que pasa .

Resumiendo: en OOP usas datos para organizar operaciones, en FP usas operaciones para organizar datos. Cada enfoque es más fuerte o más débil según el contexto. En general, ninguno de los dos tiene una mayor brecha de representación entre el problema y la solución.

Giorgio
fuente
1
En realidad, el Patrón de visitante (en OOP) te da el mismo poder que dijiste para FP. Le permite agregar nuevas operaciones mientras hace que agregar nuevas clases sea más difícil. Me pregunto si puede hacer lo mismo en FP (por ejemplo, agregar nuevos formatos en lugar de operaciones).
Eufórico
1
El escenario de procesamiento de imágenes no parece ser el mejor ejemplo. ¿Seguramente convertirías las imágenes en algún formato interno y procesarías eso en lugar de escribir implementaciones separadas de todas tus cosas de procesamiento de imágenes para cada tipo de imagen?
Hola
1
@Giorgio tal vez no obtengo el significado deseado de esta parte: "agregar nuevos formatos es más complicado: debe cambiar todas las funciones que ya ha implementado".
Hola
2
@Hey Giorgio probablemente se esté refiriendo al llamado Problema de Expresión . "Agregar nuevos formatos" significa "agregar nuevos constructores (también conocidos como" casos ") a un tipo de datos".
Andres F.
1
@Euphoric: no he examinado los detalles, pero la contraparte de FP del patrón de visitante debe involucrar una Othervariante / constructor en su tipo de datos y un parámetro de función adicional para pasar a todas las funciones para manejar el otro caso. Es, por supuesto, incómodo / menos natural con respecto a la solución OOP (despacho dinámico). Del mismo modo, el patrón de visitante es incómodo / menos natural que la solución FP (una función de orden superior).
Giorgio
5

La mayoría de los lenguajes funcionales no están orientados a objetos. Eso no significa que no tengan objetos (en el sentido de tipos complejos que tienen una funcionalidad específica asociada a ellos). Haskell, como Java, tiene listas, mapas, matrices, todo tipo de árboles y muchos otros tipos complejos. Si observa el módulo de Lista o Mapa de Haskell, verá un conjunto de funciones muy similares a los métodos en la mayoría de los módulos de biblioteca OO-language equivalentes. Si inspecciona el código, incluso encontrará una encapsulación similar, con algunos tipos (o sus constructores, para ser precisos) y funciones solo utilizables por otras funciones en el módulo.

La forma en que trabaja con estos tipos en Haskell a menudo no es muy diferente de la manera OO. En Haskell digo

  null xs
  length xs

y en Java dices

  xs.isEmpty
  xs.length

Tomate, tomate. Las funciones de Haskell no están vinculadas al objeto, pero están estrechamente asociadas con su tipo. "Ah, pero" , dices, "en Java se llama qué método de longitud es apropiado para la clase real de ese objeto". Sorpresa: Haskell también hace polimorfismo con clases de tipos (y otras cosas).

En Haskell, si tengo es una colección de enteros, no importa si la colección es una lista o conjunto o matriz, este código

  fmap (* 2) is

devolverá una colección con todos los elementos duplicados. Polimorfismo significa que se llamará a la función de mapa apropiada para el tipo específico.

Estos ejemplos no son, en verdad, tipos realmente complejos, pero lo mismo se aplica en problemas más difíciles. La idea de que los lenguajes funcionales no le permiten modelar objetos complejos y asociar funcionalidades específicas con ellos es simplemente errónea.

No hay diferencias importantes y significativas entre el estilo funcional y orientado a objetos, pero yo no lo creo esta respuesta tiene que tratar con ellos. Preguntó si los lenguajes funcionales impiden (u obstaculizan) el modelado intuitivo de problemas y tareas. La respuesta es no.

itsbruce
fuente
De hecho, puede usar clases de tipo en Java / C #; solo debe pasar explícitamente el diccionario de funciones, en lugar de hacer que el compilador deduzca el correcto según el tipo.
Doval
Oh definitivamente. Como dijo William Cook, mucho código OO en realidad hace un uso más frecuente de las funciones de orden superior que el código funcional, aunque el codificador probablemente no lo sepa.
itsbruce
2
Estás haciendo una falsa distinción. Una lista no es más una estructura de datos inerte que una pila o una cola o un simulador de tres en raya. Una lista puede contener cualquier cosa (en Haskell bien podría ser funciones parcialmente aplicadas) y define cómo se pueden interactuar con esas cosas. Puede aplicar una lista llena de funciones parcialmente aplicadas a otra lista de valores y el resultado sería una nueva lista que contiene todas las combinaciones posibles de funciones desde la primera y entrada desde la segunda. Eso es mucho más que una estructura C.
itsbruce
3
Los tipos se usan para cosas más variadas en lenguajes funcionales que los imperativos / OO (los sistemas de tipos tienden a ser más potentes y consistentes, por un lado). Los tipos y sus funciones se usan para dar forma a las rutas de código (por lo que varios lenguajes funcionales simplemente no tienen palabras clave para bucles, por ejemplo, no son necesarios).
itsbruce
44
@Fuhrmanator "No veo cómo se hace esto en FP". Entonces te estás quejando de que algo que no entiendes no tiene sentido; ve a aprenderlo, entiéndelo a fondo y entonces tendrá sentido. Tal vez, después de que tenga sentido, decidas que es una mierda y no necesitas que otros te lo demuestren, aunque otras personas como las anteriores lo entienden y no han llegado a esa conclusión. Parece que trajiste un cuchillo a un tiroteo, y ahora le estás diciendo a todos que las armas son inútiles porque no son afiladas.
Jimmy Hoffa
4

FP realmente se esfuerza por reducir la brecha representacional:

Algo que verá mucho en los lenguajes funcionales es la práctica de construir el lenguaje (usando un diseño de abajo hacia arriba) en un lenguaje específico de dominio incorporado (EDSL) . Esto le permite desarrollar un medio de expresar sus preocupaciones comerciales de una manera que sea natural para su dominio dentro del lenguaje de programación. Haskell y Lisp se enorgullecen de esto.

Parte (si no todo) de lo que permite esta capacidad es una mayor flexibilidad y expresividad dentro del idioma o los idiomas base; con funciones de primera clase, funciones de orden superior, composición de funciones y, en algunos idiomas, tipos de datos algebraicos (uniones discriminadas AKA) y la capacidad de definir operadores *, hay más flexibilidad disponible para expresar cosas que con OOP, que significa que probablemente encontrarás formas más naturales de expresar las cosas desde el dominio de tu problema. (Debería decir algo que muchos lenguajes OOP han estado adoptando muchas de estas características recientemente, si no comenzando con ellas).

* Sí, en muchos idiomas OOP puede anular los operadores estándar, pero en Haskell, puede definir otros nuevos.

En mi experiencia trabajando con lenguajes funcionales (principalmente F # y Haskell, algunos Clojure y un poco de Lisp y Erlang), me resulta más fácil mapear el espacio del problema en el lenguaje que con OOP, especialmente con tipos de datos algebraicos, que me parece más flexible que las clases. Algo que me dejó sin aliento cuando comencé con FP, particularmente con Haskell, fue que tenía que pensar / trabajar a un nivel un poco más alto de lo que estaba acostumbrado en los idiomas imperativos o POO; es posible que te encuentres con esto un poco también.

Pablo
fuente
Las preocupaciones comerciales (del cliente) no se expresan muy a menudo en las funciones de orden superior. Pero un cliente puede escribir una historia de usuario de una línea y proporcionarle reglas comerciales (o puede sacarlas del cliente). Estoy interesado en el modelado del dominio (¿de arriba hacia abajo?) (De esos artefactos) que nos permite llegar a abstracciones del problema que se asignan a funciones de primera clase, etc. ¿Puede citar algunas referencias? ¿Puedes usar un ejemplo concreto de un dominio, las abstracciones, etc.?
Fuhrmanator
3
@Fuhrmanator Un cliente aún puede escribir historias de usuario de una línea y reglas comerciales independientemente de si usa OOP y FP . No espero que los clientes comprendan las funciones de orden superior más de lo que espero que comprendan la herencia, la composición o las interfaces.
Andres F.
1
@Fuhrmanator ¿Con qué frecuencia ha hecho que el cliente exprese sus preocupaciones en términos de genéricos de Java o clases e interfaces base abstractas? Querido Dios. Paul le ha dado una muy buena respuesta, explicando un método práctico y confiable de modelado utilizando técnicas que seguramente no son demasiado difíciles de visualizar. Y, sin embargo, insiste en que se describa en términos de una técnica de modelado específica para un paradigma en particular, como si esa fuera de alguna manera la forma más natural de representar el diseño y cualquier otra cosa pueda ser rediseñada en sus términos.
itsbruce
@Fuhrmanator Esto podría no ser tan de alto nivel como está buscando, pero debería dar una idea del proceso de diseño utilizando técnicas funcionales: Diseño con tipos . Recomiendo navegar por ese sitio en general porque tiene algunos artículos excelentes.
Paul
@Fuhrmanator También hay esta serie Thinking Functionally
Paul
3

Como dijo Niklaus Wirth, "Algoritmos + Estructuras de datos = Programas". La programación funcional trata sobre la forma de organizar algoritmos, y no dice mucho sobre cómo organizar estructuras de datos. De hecho, existen lenguajes FP tanto con variables mutables (Lisp) como inmutables (Haskell, Erlang). Si desea comparar y contrastar FP con algo, debe elegir la programación imperativa (C, Java) y declarativa (Prolog).

OOP es, por otro lado, una forma de construir estructuras de datos y adjuntarles algoritmos. FP no le impide construir estructuras de datos similares a las de OOP. Si no me cree, eche un vistazo a las declaraciones de tipo Haskell. Sin embargo, la mayoría de los lenguajes FP están de acuerdo en que las funciones no pertenecen a estructuras de datos y deberían estar en el mismo espacio de nombres. Esto se hace para simplificar la construcción de nuevos algoritmos a través de la composición de funciones. De hecho, si sabe qué entrada toma una función y qué salida produce, ¿por qué debería importar a qué estructura de datos pertenece también? Por ejemplo, ¿por qué addse debe llamar a la función en una instancia de tipo Integer y pasar un argumento en lugar de simplemente pasar dos argumentos Integer?

Por lo tanto, no veo por qué FP debería hacer que las soluciones sean más difíciles de entender en general, y no creo que lo haga de todos modos. Sin embargo, tenga en cuenta que un programador imperativo experimentado seguramente encontrará los programas funcionales más difíciles de entender que los imperativos, y viceversa. Esto es similar a Windows: la dicotomía de Linux cuando las personas que han invertido 10 años en sentirse cómodos con el entorno de Windows encuentran que Linux es difícil después de un mes de uso, y aquellos que están acostumbrados a Linux no pueden lograr la misma productividad en Windows. Por lo tanto, la 'brecha representacional' de la que estás hablando es muy subjetiva.

mkalkov
fuente
Debido a la encapsulación y la ocultación de datos, que no son principios OO per se, no estoy completamente de acuerdo con que OO sean estructuras de datos + algoritmos (esa es solo la vista interna). La belleza de cualquier buena abstracción es que hay algún servicio que brinda para resolver parte del problema, sin necesidad de comprender demasiados detalles. Creo que estás hablando de encapsulación cuando separas funciones y datos en FP, pero soy demasiado ecológico para estar seguro. Además, edité mi pregunta para referirme al rastreo desde la solución hasta el problema (para aclarar el significado de la brecha de representación).
Fuhrmanator
if you know what input a function takes and what output it produces, why should it matter which data structure it belongs too?Eso se parece mucho a la cohesión, que para cualquier sistema modular es importante. Yo diría que no saber dónde encontrar una función dificultaría la comprensión de una solución, lo que se debe a una mayor brecha de representación. Muchos sistemas OO tienen este problema, pero se debe a un mal diseño (baja cohesión). Una vez más, el problema del espacio de nombres está fuera de mi experiencia en FP, por lo que tal vez no sea tan malo como parece.
Fuhrmanator
1
@Fuhrmanator Pero usted no sabe dónde encontrar una función. Y solo hay una función, no múltiples funciones con el mismo nombre, definidas para cada tipo de datos (de nuevo, consulte el "Problema de expresión"). Por ejemplo, para las funciones de la biblioteca Haskell (que se recomienda usar, en lugar de redescubrir la rueda o hacer versiones ligeramente menos útiles de dichas funciones), tiene herramientas de descubrimiento maravillosas como Hoogle , que es tan potente que le permite buscar por firma (¡pruébalo! :))
Andres F.
1
@Fuhrmanator, después de "Eso suena muy parecido a la cohesión", hubiera esperado que concluyeras lógicamente que los lenguajes FP te permiten escribir programas con mayor cohesión, pero me sorprendiste. :-) Creo que deberías elegir un lenguaje FP, aprenderlo y decidir el tuyo. Si yo fuera usted, sugeriría comenzar con Haskell ya que es bastante puro y, por lo tanto, no le permitirá escribir código con un estilo imperativo. Erlang y algunos Lisp también son buenas opciones, pero se mezclan en otros estilos de programación. Scala y Clojure, IMO, son bastante complicados para comenzar.
mkalkov