¿Cuál es una buena manera de diseñar/estructurar programas funcionales grandes, especialmente en Haskell?Diseño a gran escala en Haskell?
He pasado por muchos de los tutoriales (Write Yourself a Scheme es mi favorito, con Real World Haskell en un segundo plano), pero la mayoría de los programas son relativamente pequeños y de un solo propósito. Además, no considero que algunos de ellos sean particularmente elegantes (por ejemplo, las vastas tablas de búsqueda en WYAS).
Ahora quiero escribir programas más grandes, con más partes móviles: adquirir datos de una variedad de fuentes diferentes, limpiarlo, procesarlo de varias maneras, mostrarlo en las interfaces de usuario, conservarlo, comunicarme a través de redes, ¿Cómo podría uno estructurar mejor dicho código para ser legible, mantenible y adaptable a los requisitos cambiantes?
Hay una gran cantidad de literatura que aborda estas cuestiones para grandes programas imperativos orientados a objetos. Ideas como MVC, patrones de diseño, etc. son recetas decentes para realizar objetivos amplios como la separación de preocupaciones y la reutilización en un estilo OO. Además, los nuevos lenguajes imperativos se prestan a un estilo de refactorización de 'diseño a medida que creces', al cual, en mi opinión de novato, Haskell parece menos adecuado.
¿Existe literatura equivalente para Haskell? ¿Cómo está disponible el zoológico de estructuras de control exóticas en la programación funcional (mónadas, flechas, aplicativo, etc.) mejor empleadas para este propósito? ¿Qué mejores prácticas podrías recomendar?
Gracias!
EDITAR (esto es un seguimiento de la respuesta de Don Stewart):
@dons mencionan: "mónadas capturar diseños arquitectónicos clave en los tipos"
Supongo que mi pregunta es: ¿cómo se debe pensar sobre los diseños arquitectónicos clave en un lenguaje funcional puro?
Considere el ejemplo de varias secuencias de datos y varios pasos de procesamiento. Puedo escribir analizadores modulares para las secuencias de datos en un conjunto de estructuras de datos, y puedo implementar cada paso de procesamiento como una función pura. Los pasos de procesamiento requeridos para una pieza de datos dependerán de su valor y de los demás. Algunos de los pasos deberían ir seguidos de efectos colaterales, como actualizaciones de la GUI o consultas a la base de datos.
¿Cuál es la forma "correcta" de vincular los datos y los pasos de análisis de una manera agradable? Uno podría escribir una gran función que hace lo correcto para los diversos tipos de datos. O uno podría usar una mónada para realizar un seguimiento de lo que se ha procesado hasta el momento y hacer que cada paso de procesamiento obtenga lo que necesite a partir del estado de la mónada. O uno podría escribir programas bastante separados y enviar mensajes (no me gusta mucho esta opción).
Las diapositivas que vinculan tienen una cosa que necesitamos viñeta: "Modismos para el diseño de mapeo en tipos/funciones/clases/mónadas". ¿Cuáles son los modismos? :)
Creo que la idea principal cuando se escriben programas grandes en un lenguaje funcional es * módulos pequeños, especializados y sin estado que se comunican a través del envío de mensajes *. Por supuesto, tienes que fingir un poco porque un verdadero programa necesita estado. Creo que aquí es donde F # brilla sobre Haskell. – ChaosPandion
@Chaos pero solo Haskell impone la apatridia de forma predeterminada. No tiene otra opción, y tiene que trabajar duro para introducir el estado (para romper la composicionalidad) en Haskell :-) –
@Don - Sí, lo sé, pero soy uno de los mejores ambos mundos tipo chicos. – ChaosPandion