Was ist ein guter Weg, um große Funktionsprogramme zu entwerfen / strukturieren, insbesondere in Haskell?
Ich habe eine Reihe von Tutorials durchlaufen (Write Yourself a Scheme ist mein Favorit, Real World Haskell steht an zweiter Stelle) - aber die meisten Programme sind relativ klein und für einen bestimmten Zweck bestimmt. Darüber hinaus halte ich einige von ihnen nicht für besonders elegant (zum Beispiel die umfangreichen Nachschlagetabellen in WYAS).
Ich möchte jetzt größere Programme mit beweglicheren Teilen schreiben - Daten aus verschiedenen Quellen erfassen, bereinigen, auf verschiedene Arten verarbeiten, in Benutzeroberflächen anzeigen, beibehalten, über Netzwerke kommunizieren usw. Wie könnte Eine beste Struktur, um solchen Code lesbar, wartbar und an sich ändernde Anforderungen anpassbar zu machen?
Es gibt eine ziemlich große Literatur, die sich mit diesen Fragen für große objektorientierte imperative Programme befasst. Ideen wie MVC, Entwurfsmuster usw. sind anständige Vorschriften zur Verwirklichung umfassender Ziele wie der Trennung von Bedenken und der Wiederverwendbarkeit in einem OO-Stil. Darüber hinaus eignen sich neuere imperative Sprachen für einen Refactoring-Stil, für den Haskell meiner Meinung nach weniger geeignet ist.
Gibt es eine gleichwertige Literatur für Haskell? Wie wird der Zoo exotischer Kontrollstrukturen, die in der funktionalen Programmierung verfügbar sind (Monaden, Pfeile, Applikative usw.), für diesen Zweck am besten eingesetzt? Welche Best Practices können Sie empfehlen?
Vielen Dank!
EDIT (dies ist eine Fortsetzung der Antwort von Don Stewart):
@dons erwähnt: "Monaden erfassen wichtige architektonische Entwürfe in Typen."
Ich denke meine Frage ist: Wie sollte man über wichtige architektonische Entwürfe in einer reinen funktionalen Sprache denken?
Betrachten Sie das Beispiel mehrerer Datenströme und mehrerer Verarbeitungsschritte. Ich kann modulare Parser für die Datenströme in eine Reihe von Datenstrukturen schreiben und jeden Verarbeitungsschritt als reine Funktion implementieren. Die für ein Datenelement erforderlichen Verarbeitungsschritte hängen von seinem Wert und dem anderer Daten ab. Auf einige der Schritte sollten Nebenwirkungen wie GUI-Updates oder Datenbankabfragen folgen.
Was ist der richtige Weg, um die Daten und die Parsing-Schritte auf nette Weise zu verknüpfen? Man könnte eine große Funktion schreiben, die für die verschiedenen Datentypen das Richtige tut. Oder man könnte eine Monade verwenden, um zu verfolgen, was bisher verarbeitet wurde, und jeden Verarbeitungsschritt vom Monadenstatus alles bekommen zu lassen, was er als nächstes benötigt. Oder man könnte weitgehend separate Programme schreiben und Nachrichten senden (diese Option gefällt mir nicht besonders).
Die Folien, die er verlinkt hat, haben eine Aufzählungszeichen: "Redewendungen für die Zuordnung von Design zu Typen / Funktionen / Klassen / Monaden". Was sind die Redewendungen? :) :)