Wann möchten Sie KEINE funktionale Programmierung verwenden? Was kann es nicht so gut?
Ich bin eher auf der Suche nach Nachteilen des gesamten Paradigmas, nicht nach Dingen wie "nicht weit verbreitet" oder "kein guter Debugger verfügbar". Diese Antworten mögen ab sofort richtig sein, aber sie befassen sich damit, dass FP ein neues Konzept ist (ein unvermeidbares Problem) und keine inhärenten Eigenschaften.
Verbunden:
functional-programming
paradigms
Gordon Gustafson
quelle
quelle
Antworten:
Es fällt mir schwer, an viele Nachteile der funktionalen Programmierung zu denken. Andererseits bin ich ein ehemaliger Vorsitzender der Internationalen Konferenz für funktionale Programmierung, also können Sie sicher annehmen, dass ich voreingenommen bin.
Ich denke, die Hauptnachteile haben mit Isolation und Eintrittsbarrieren zu tun. Das Lernen, gute funktionale Programme zu schreiben , bedeutet, zu lernen, anders zu denken, und es gut zu machen, erfordert einen erheblichen Aufwand an Zeit und Mühe . Ohne Lehrer ist es schwierig zu lernen. Diese Eigenschaften führen zu einigen Nachteilen:
Es ist wahrscheinlich, dass ein von einem Neuling geschriebenes Funktionsprogramm unnötig langsam ist - wahrscheinlicher als beispielsweise ein von einem Neuling in C geschriebenes C-Programm. Andererseits ist es ungefähr genauso wahrscheinlich, dass ein von einem Neuling geschriebenes C ++ - Programm wird unnötig langsam sein. (All diese glänzenden Eigenschaften ...)
Im Allgemeinen haben Experten keine Schwierigkeiten, schnelle Funktionsprogramme zu schreiben. Tatsächlich sind einige der leistungsstärksten Parallelprogramme auf 8- und 16-Kern-Prozessoren jetzt in Haskell geschrieben .
Es ist wahrscheinlicher, dass jemand, der mit der funktionalen Programmierung beginnt, aufgibt, bevor er die versprochenen Produktivitätsgewinne realisiert, als jemand, der beispielsweise Python oder Visual Basic startet. Es gibt einfach nicht so viel Unterstützung in Form von Büchern und Entwicklungswerkzeugen.
Es gibt weniger Leute, mit denen man reden kann. Stackoverflow ist ein gutes Beispiel; relativ wenige Haskell-Programmierer besuchen die Site regelmäßig (obwohl ein Teil davon darin besteht, dass Haskell-Programmierer ihre eigenen lebhaften Foren haben, die viel älter und besser etabliert sind als Stackoverflow).
Es ist auch wahr, dass Sie nicht so einfach mit Ihrem Nachbarn sprechen können, da funktionale Programmierkonzepte schwieriger zu lehren und zu lernen sind als die objektorientierten Konzepte hinter Sprachen wie Smalltalk, Ruby und C ++. Außerdem hat die objektorientierte Community jahrelang gute Erklärungen für ihre Arbeit entwickelt, während die Community für funktionale Programmierung zu denken scheint, dass ihre Inhalte offensichtlich großartig sind und keine speziellen Metaphern oder Vokabeln zur Erklärung benötigen. (Sie sind falsch. Ich warte immer noch auf das erste großartige Buch Functional Design Patterns .)
Ein bekannter Nachteil der verzögerten Funktionsprogrammierung (gilt für Haskell oder Clean, jedoch nicht für ML oder Scheme oder Clojure) ist, dass es sehr schwierig ist, die Zeit- und Raumkosten für die Bewertung eines verzögerten Funktionsprogramms vorherzusagen - selbst Experten können dies nicht es. Dieses Problem ist grundlegend für das Paradigma und verschwindet nicht. Es gibt ausgezeichnete Werkzeuge, um das Verhalten von Zeit und Raum post facto zu entdecken , aber um sie effektiv zu nutzen, müssen Sie bereits Experte sein.
quelle
Ein großer Nachteil der funktionalen Programmierung besteht darin, dass sie theoretisch nicht mit der Hardware und den meisten wichtigen Sprachen übereinstimmt. (Dies ist die Kehrseite einer seiner offensichtlichen Stärken: Sie können ausdrücken, was Sie tun möchten, anstatt wie der Computer es tun soll.)
Beispielsweise nutzt die funktionale Programmierung die Rekursion stark. Dies ist in der reinen Lambda-Rechnung in Ordnung, da der "Stapel" der Mathematik unbegrenzt ist. Natürlich ist der Stack auf echter Hardware sehr begrenzt. Das naive Rekursieren über einen großen Datensatz kann Ihr Programm zum Boom bringen. Die meisten funktionalen Sprachen optimieren die Schwanzrekursion so, dass dies nicht geschieht. Wenn Sie jedoch einen Algorithmus für die Schwanzrekursion verwenden, können Sie zu einer ziemlich unschönen Codegymnastik gezwungen werden (z. B. erstellt eine Schwanzrekursionskartenfunktion eine Rückwärtsliste oder muss einen Unterschied aufbauen Liste, daher muss zusätzliche Arbeit geleistet werden, um zu einer normalen zugeordneten Liste in der richtigen Reihenfolge im Vergleich zur nicht-rekursiven Version zurückzukehren.
(Danke an Jared Updike für den Vorschlag zur Differenzliste.)
quelle
map
und schwanzrekursivrev_map
).Wenn Ihre Sprache keine guten Mechanismen bietet, um das Status- / Ausnahmeverhalten über Ihr Programm auszuloten (z. B. Syntaxzucker für monadische Bindungen), wird jede Aufgabe, die Status / Ausnahmen umfasst, zur Pflicht. (Selbst mit diesen Zuckern fällt es einigen Menschen möglicherweise schwerer, mit Zuständen / Ausnahmen in FP umzugehen.)
Funktionale Redewendungen führen häufig zu einer starken Umkehrung der Kontrolle oder Faulheit, was sich häufig negativ auf das Debuggen auswirkt (mithilfe eines Debuggers). (Dies wird etwas dadurch ausgeglichen, dass FP aufgrund von Unveränderlichkeit / referenzieller Transparenz viel weniger fehleranfällig ist, was bedeutet, dass Sie weniger häufig debuggen müssen.)
quelle
Philip Wadler schrieb einen Artikel darüber (Warum niemand funktionale Programmiersprachen verwendet) und ging auf die praktischen Fallstricke ein, die Menschen davon abhalten, FP-Sprachen zu verwenden:
Update: Unzugänglicher alter Link für Benutzer mit ACM-Zugriff:
quelle
Abgesehen von Geschwindigkeits- oder Adoptionsproblemen und der Behebung eines grundlegenderen Problems habe ich gehört, dass es mit funktionaler Programmierung sehr einfach ist, neue Funktionen für vorhandene Datentypen hinzuzufügen, aber es ist "schwierig", neue Datentypen hinzuzufügen. Erwägen:
(Geschrieben in SMLnj. Bitte entschuldigen Sie auch das etwas erfundene Beispiel.)
Ich kann sehr schnell Folgendes hinzufügen:
Wenn ich jedoch einen neuen Typ zu Animal hinzufüge, muss ich jede Funktion durchgehen, um Unterstützung dafür hinzuzufügen:
Beachten Sie jedoch, dass für objektorientierte Sprachen genau das Gegenteil der Fall ist. Es ist sehr einfach, einer abstrakten Klasse eine neue Unterklasse hinzuzufügen, aber es kann mühsam sein, wenn Sie der abstrakten Klasse / Schnittstelle eine neue abstrakte Methode hinzufügen möchten, damit alle Unterklassen implementiert werden können.
quelle
Ich wollte nur mit einer Anekdote anfangen, weil ich gerade Haskell lerne, während wir sprechen. Ich lerne Haskell, weil mir die Idee gefällt, Funktionen von Aktionen zu trennen, und es gibt einige wirklich sexy Theorien hinter der impliziten Parallelisierung, weil reine Funktionen von nicht reinen Funktionen isoliert werden.
Ich lerne jetzt seit drei Tagen die Fold-Funktionsklasse. Fold scheint eine sehr einfache Anwendung zu haben: eine Liste zu nehmen und sie auf einen einzigen Wert zu reduzieren. Haskell implementiert a
foldl
undfoldr
dafür. Die beiden Funktionen haben sehr unterschiedliche Implementierungen. Es gibt eine alternative Implementierung vonfoldl
, genanntfoldl'
. Darüber hinaus gibt es eine Version mit einer etwas anderen Syntaxfoldr1
undfoldl1
unterschiedlichen Anfangswerten. Davon gibt es eine entsprechende Implementierung vonfoldl1'
forfoldl1
. Als ob all dies nicht umwerfend wäre, funktionieren die Funktionenfold[lr].*
erfordern als Argumente und verwenden intern in der Reduktion haben zwei separate Signaturen, nur eine Variante arbeitet auf unendlichen Listen (r), und nur eine von ihnen wird im konstanten Speicher ausgeführt (wie ich verstehe (L), weil nur es erfordert aredex
).foldr
Um zu verstehen, warum mit unendlichen Listen gearbeitet werden kann, ist zumindest ein gutes Verständnis der Sprachen Lazy-Behavoir und des kleinen Details erforderlich, dass nicht alle Funktionen die Bewertung des zweiten Arguments erzwingen. Die Online-Grafiken für diese Funktionen sind für jemanden, der sie im College noch nie gesehen hat, verdammt verwirrend. Es gibt keinperldoc
Äquivalent. Ich kann keine einzige Beschreibung finden, was eine der Funktionen im Haskell-Vorspiel bewirkt. Das Vorspiel ist eine Art vorinstallierte Distribution, die mit dem Kern geliefert wird. Meine beste Ressource ist wirklich ein Typ, den ich noch nie getroffen habe (Cale), der mir mit enormen Kosten für seine eigene Zeit hilft.Oh, und Fold muss die Liste nicht auf einen Skalar ohne Listentyp reduzieren. Die Identitätsfunktion für Listen kann geschrieben werden
foldr (:) [] [1,2,3,4]
(Hervorhebungen, die Sie in einer Liste sammeln können).Ich gehe zurück zum Lesen.
quelle
Hier sind einige Probleme, auf die ich gestoßen bin:
quelle
Wenn ich von den Details spezifischer Implementierungen der funktionalen Programmierung wegschaue, sehe ich zwei Hauptprobleme:
Es scheint vergleichsweise selten, dass es praktisch ist, ein Funktionsmodell eines realen Problems einem imperativen vorzuziehen. Wenn die Problemdomäne unbedingt erforderlich ist, ist die Verwendung einer Sprache mit diesem Merkmal eine natürliche und vernünftige Wahl (da es im Allgemeinen ratsam ist, den Abstand zwischen Spezifikation und Implementierung zu minimieren, um die Anzahl subtiler Fehler zu verringern). Ja, dies kann durch einen ausreichend intelligenten Codierer überwunden werden. Wenn Sie jedoch Rockstar-Codierer für diese Aufgabe benötigen, liegt dies daran, dass es zu blutig ist.
Aus irgendeinem Grund, den ich nie wirklich verstanden habe, möchten funktionale Programmiersprachen (oder vielleicht ihre Implementierungen oder Communitys?) Viel eher alles in ihrer Sprache haben. Bibliotheken, die in anderen Sprachen geschrieben sind, werden viel weniger verwendet. Wenn jemand anderes eine besonders gute Implementierung einer komplexen Operation hat, ist es viel sinnvoller, diese zu verwenden, anstatt eine eigene zu erstellen. Ich vermute, dass dies teilweise auf die Verwendung komplexer Laufzeiten zurückzuführen ist, die den Umgang mit Fremdcode (und insbesondere die effiziente Ausführung) ziemlich schwierig machen. Ich würde gerne in diesem Punkt als falsch erwiesen werden.
Ich nehme an, dass beide auf einen allgemeinen Mangel an Pragmatismus zurückzuführen sind, der dadurch verursacht wird, dass funktionale Programmierung von Programmierforschern viel stärker verwendet wird als gewöhnliche Codierer. Ein gutes Werkzeug kann es einem Experten ermöglichen, großartige Dinge zu tun, aber ein großartiges Werkzeug ermöglicht es dem einfachen Mann, sich dem zu nähern, was ein Experte normalerweise tun kann, da dies bei weitem die schwierigere Aufgabe ist.
quelle