Wie gestaltet man Programme in Haskell oder anderen funktionalen Programmiersprachen?


52

Ich habe einige Erfahrung in objektorientierten Programmiersprachen wie C # oder Ruby. Ich weiß, wie man ein Programm im objektorientierten Stil erstellt, wie man Klassen und Objekte erstellt und wie man Beziehungen zwischen ihnen definiert. Ich kenne auch einige Designmuster.

Wie schreiben Menschen funktionale Programme? Wie fangen sie an? Gibt es Entwurfsmuster für funktionale Sprachen? Sind Methoden wie extreme Programmierung oder agile Entwicklung für funktionale Sprachen anwendbar?


Antworten:


24

Ich schreibe meine Antwort hauptsächlich mit Blick auf Haskell, obwohl viele Konzepte auch für andere funktionale Sprachen wie Erlang, Lisp (s) und ML gelten. Einige gelten (in gewissem Umfang) sogar für Ruby, Python, Perl und Javascript.

Wie schreiben Menschen funktionale Programme? Wie fangen sie an?

Durch das Schreiben von Funktionen. Beim funktionalen Programmieren schreiben Sie entweder mainoder Sie schreiben eine Hilfsfunktion. Manchmal kann es Ihr Hauptziel sein, einen Datentyp mit verschiedenen relevanten Funktionen zu schreiben, die darauf arbeiten.

Die funktionale Programmierung eignet sich sowohl für Top-Down- als auch für Bottom-Up-Ansätze. Haskell empfiehlt nachdrücklich, Ihre Programme in Hochsprache zu schreiben und dann einfach die Details Ihres Hochentwurfs zu definieren. Siehe minimumzum Beispiel:

minimum    :: (Ord a) => [a] -> a
minimum xs =  foldl1 min xs

Die Funktion zum Auffinden des kleinsten Elements in einer Liste wird einfach als Durchlauf über die Liste geschrieben, wobei die Funktion min verwendet wird, um jedes Element mit dem "Akkumulator" oder dem aktuellen Mindestwert zu vergleichen.

Gibt es Entwurfsmuster für funktionale Sprachen?

Es gibt zwei Dinge, die mit "Entwurfsmustern" gleichgesetzt werden könnten, imho, Funktionen höherer Ordnung und Monaden . Reden wir über Ersteres. Funktionen höherer Ordnung sind Funktionen, die entweder andere Funktionen als Eingabe annehmen oder Funktionen als Ausgabe erzeugen. Jede funktionale Sprache macht in der Regel starke Nutzung von map, filterundfold(fold wird oft auch als "reduct" bezeichnet): drei sehr grundlegende Funktionen höherer Ordnung, die eine Funktion auf unterschiedliche Weise auf eine Liste anwenden. Diese ersetzen auf schöne Weise die Heizplatte für Schleifen. Das Weitergeben von Funktionen als Parameter ist ein äußerst wichtiger Vorteil für die Programmierung. Viele "Entwurfsmuster" lassen sich einfacher erstellen, indem Funktionen höherer Ordnung verwendet werden, eigene Funktionen erstellt werden und die leistungsstarke Standardbibliothek mit zahlreichen nützlichen Funktionen genutzt wird.

Monaden sind das "gruseligere" Thema. Aber sie sind nicht wirklich so beängstigend. Meine liebste Art, an Monaden zu denken, ist, sie als eine Funktion in eine Blase einhüllend zu betrachten und dieser Funktion Superkräfte zu verleihen (die nur innerhalb der Blase funktionieren). Ich könnte näher darauf eingehen, aber die Welt braucht nicht wirklich eine weitere Monadenanalogie. Also gehe ich zu kurzen Beispielen über. Angenommen, ich möchte ein nicht deterministisches "Entwurfsmuster" verwenden. Ich möchte die gleiche Berechnung für verschiedene Eingaben gleichzeitig ausführen. Ich möchte nicht nur einen Eingang auswählen, ich möchte sie alle auswählen. Das wäre die Listenmonade:

allPlus2 :: [Int] -> [Int]
allPlus2 xs = do x <- xs
                 return (x + 2)

Nun, die idiomatische Art, dies durchzuführen, ist tatsächlich map, aber zur Veranschaulichung, können Sie sehen, wie die Listenmonade es mir ermöglichte, eine Funktion zu schreiben, die aussieht, als würde sie auf einen Wert angewendet, aber mit der Superkraft ausgestattet, an jedem Element in zu arbeiten eine Liste? Andere Supermächte sind Versagen, Staat, Interaktion mit der "Außenwelt" und parallele Ausführung. Diese Superkräfte sind sehr mächtig, und die meisten Programmiersprachen ermöglichen es Funktionen mit Superkräften, überall herum zu toben. Die meisten Leute sagen, dass Haskell diese Supermächte überhaupt nicht zulässt, aber tatsächlich enthält Haskell sie nur in Monaden, so dass ihre Wirkung begrenzt und beobachtet werden kann.

Grokking Funktionen und Monaden höherer Ordnung ist das Haskell-Äquivalent zu Grokking-Entwurfsmustern. Sobald Sie diese Haskell-Konzepte kennengelernt haben, denken Sie, dass "Design Patterns" meist günstige Workarounds sind, um die Leistungsfähigkeit von Haskell zu simulieren.

Sind Methoden wie extreme Programmierung oder agile Entwicklung für funktionale Sprachen anwendbar?

Ich sehe nichts, was diese Managementstrategien an ein Programmierparadigma knüpft. Wie phynfo bereits sagte, zwingt die funktionale Programmierung Sie praktisch dazu, eine Funktionszerlegung durchzuführen , bei der ein großes Problem in Teilprobleme zerlegt wird. Mini-Meilensteine ​​sollten also ein Kinderspiel sein. Es gibt Tools wie QuickCheck und Zeno, mit denen Sie Eigenschaften der von Ihnen geschriebenen Funktionen testen oder sogar nachweisen können.


"Ich könnte näher darauf eingehen, aber die Welt braucht nicht wirklich eine weitere Monadenanalogie." - Wir brauchen immer mehr Analogien für Monaden und deine ist eine der besten, die ich je gesehen habe.
Adam Gent

1
Gute Antwort, aber ich denke, Ihre Diskussion über Designmuster ist ein wenig irreführend. Während Sie in Haskell keine Designmuster im OO / GOF-Stil benötigen - es wäre sogar lächerlich, sie zu versuchen -, sind Muster selbst einfach Wege, wie eine Community Lösungen für die Probleme kommuniziert, die immer wieder auftauchen. Die Haskell-Community ist noch sehr jung, daher gibt es noch nicht viele Muster, über die man sprechen kann. Wenn Sie mich jedoch nach Beispielen für Haskell-Muster fragen, würde ich Dinge wie GADTs oder Arrowized FRP erwähnen.
RTPerson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.