¿Cuál es una buena manera de diseñar / estructurar grandes programas funcionales, especialmente en Haskell?
He pasado por un montón de tutoriales (Write Yourself a Scheme es mi favorito, con Real World Haskell en segundo lugar), 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, limpiarlos, procesarlos de varias maneras, mostrarlos en las interfaces de usuario, persistir, comunicarse a través de redes, etc. ¿Cómo podría ¿Cuál es la mejor estructura para que ese código sea legible, mantenible y adaptable a los requisitos cambiantes?
Existe una literatura bastante extensa que aborda estas preguntas para grandes programas imperativos orientados a objetos. Ideas como MVC, patrones de diseño, etc. son recetas decentes para alcanzar 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" para el que, en mi opinión de principiante, Haskell parece menos adecuado.
¿Existe una literatura equivalente para Haskell? ¿Cómo se emplea mejor el zoológico de estructuras de control exóticas en programación funcional (mónadas, flechas, aplicativo, etc.) para este propósito? ¿Qué mejores prácticas podrías recomendar?
¡Gracias!
EDITAR (esto es un seguimiento de la respuesta de Don Stewart):
@dons mencionó: "Las mónadas capturan diseños arquitectónicos clave en tipos".
Supongo que mi pregunta es: ¿cómo debería uno pensar en los diseños arquitectónicos clave en un lenguaje funcional puro?
Considere el ejemplo de varios flujos de datos y varios pasos de procesamiento. Puedo escribir analizadores modulares para los flujos 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 necesarios para una pieza de datos dependerán de su valor y de los demás. Algunos de los pasos deben ser seguidos por efectos secundarios como actualizaciones de GUI o consultas de bases de datos.
¿Cuál es la forma 'correcta' de vincular los datos y los pasos de análisis de una manera agradable? Se podría escribir una gran función que haga lo correcto para los distintos tipos de datos. O se podría usar una mónada para realizar un seguimiento de lo que se ha procesado hasta ahora y hacer que cada paso de procesamiento obtenga lo que necesite a continuación del estado de la mónada. O uno podría escribir programas en gran parte separados y enviar mensajes (no me gusta mucho esta opción).
Las diapositivas que vinculó tienen una viñeta de Cosas que necesitamos: "Modismos para mapear el diseño en tipos / funciones / clases / mónadas". ¿Cuáles son los modismos? :)