Fügt die funktionale Programmierung dem Code Komplexität hinzu? [geschlossen]

17

Für das gesamte vergangene Jahr habe ich Scala- Code geschrieben (mit Java-Hintergrund). Es hat mir sehr gut gefallen, wie Sie einfacheren und saubereren Code mit Vals, Case-Klassen, Map / Filter / Lambda-Funktionen, Implicits und der Typinferenz erstellen können. Ich habe es hauptsächlich für eine Akka- basierte Anwendung verwendet.

Dieses Jahr bin ich in einem Scala-Projekt mit einem neuen Team, das funktionale Programmierung wirklich mag. Sie verwenden häufig Scalaz , und der Code ist überall mit Anwendern, Kontextgrenzen, Lese- / Schreib- / Statusmonaden gefüllt, selbst die Hauptmethode ist in eine E / A-Monade "eingepackt". Ihre Argumentation ist, dass dies den Compiler dazu bringt, "für uns zu arbeiten", zu behaupten, dass der Code korrekt ist und jede Funktion frei von Nebenwirkungen ist.

Trotzdem steht aus meiner Sicht all diese Syntax der Geschäftslogik im Weg. Ein Typ von "MyBusinessObject" ist beispielsweise in Ordnung, ebenso wie Typen wie "List [MyBusinessObject]", "Option [MyBusinessObject]" oder sogar "Future [MyBusinessObject]". Sie alle haben eine klare Bedeutung und einen klaren Zweck. Auf der anderen Seite Code wie:

def method[M[_]: Applicative] = {
  case (a, b) => (ca[M](a) |@| cb[M](b)) {
    case t @ (ra, rb) =>
      if (ra.result && rb.result) t.right
      else t.left
  }
}

Fügt es dem Programm Komplexität hinzu, oder bin ich nur an diese Art der Programmierung nicht gewöhnt?

Luciano
quelle
6
Was ist Ihre objektiv zu beantwortende Frage?
Deer Hunter
1
Sieht so aus, als würde es zu einer Menge Code mit ein- oder zweistelligen Variablennamen führen. Sieht nach APL aus. Das ist keine Ergänzung.
user949300
3
Ich habe letztes Jahr angefangen, mit Haskell zu spielen. Es sah zu der Zeit unglaublich komplex aus, als ich Konzepte wie Curry, Funktoren, Monaden usw. nicht verstand. Haskell ähnelt Scalaz darin, dass es viele kurze, symbolische Funktionen hat, wie >>=und <$>, die bis auf Sie nichts bedeuten wissen was sie tun. Nachdem sie gelernt haben, was sie bedeuten, lesen sie mir jetzt ganz natürlich und schnell vor. Keine wirkliche Antwort, nur meine objektive Erfahrung mit solchen Dingen. Ich benutze auch Scala, habe aber keine Erfahrung mit der Scalaz-Bibliothek.
KChaloux
3
Sie kennen die Redewendungen einfach nicht. @ user949300 kurze Variablen sind für viele Funktionscodes kein wirkliches Problem (denken Sie an mathematische Konventionen!). Lesen Sie auch Tony Morris 'Blog für eine eingehendere Diskussion darüber, was Bedeutungen, Typen oder ausführliche Variablennamen besser vermittelt.
Andres F.
3
@ user949300: Kurze Variablennamen werden lokal bevorzugt, das ist in der funktionalen und der imperativen Welt dasselbe (Sie würden doch nicht for(i=0; i<7; ++i) { trivialOperation(i); }mit einer umständlichen trivialOperationCountVariablen schreiben , oder?). In funktionalen Programmiersprachen mit Pattern Matching werden manchmal weitere Variablen eingeführt schreibe einfach Accessor Methodenaufrufe in OO aus. Das Ergebnis ist im Allgemeinen prägnanter. Vielleicht ein bisschen weniger selbsterklärend, aber das Nachschlagen der Datendeklaration macht es normalerweise schnell klar. Statische Eingabe hilft sehr, es ist nicht wie in APL.
Leftaroundabout

Antworten:

37

Dies hat nichts mit funktionaler Programmierung zu tun - Sie können diese Art von Situation im Kontext jeder anderen Programmiersprache finden - Entwickler, die die fortgeschrittenen Konstrukte "ihrer" Sprache so sehr lieben, dass sie jeglichen gesunden Menschenverstand in Bezug auf Lesbarkeit und einfache Dinge ignorieren. Ich habe eine solche Situation in C, C ++, Perl, Java, C #, Basic und anderen nicht funktionierenden Sprachen erlebt. Es ist nicht die funktionale Programmierung, die dem Code Komplexität verleiht - das tun Programmierer.

Verstehen Sie mich nicht falsch, ich empfehle nicht, erweiterte Sprachfunktionen zu vermeiden - aber es ist wichtig, das richtige Gleichgewicht im gegebenen Kontext zu finden. Wenn Sie eine generische Bibliothek für die Verwendung von mehr als 100.000 Entwicklern auf der ganzen Welt schreiben, müssen Sie unterschiedliche Maßnahmen anwenden, als würden Sie einen individuellen Berichtsgenerator nur für Ihr lokales Büro schreiben.

Doc Brown
quelle
7
Es hat auch viel mit der Community zu tun. Für Entwickler mit Java- oder C # -Hintergrund ist der Code kaum verständlich (und seine Community würde ihn auch nicht verstehen). Aber wenn Sie zum Beispiel Haskell schreiben und keine Monaden, Anwendungsprogramme, Funktoren usw. verwenden, verwirren Sie die Community dieser Sprache. Die "Natürlichkeit" des Codes ist nicht inhärent, sondern relativ zu seiner Gemeinschaft und den etablierten Praktiken.
Andres F.
1
Dies ist schwer zu erkennen, da die meisten von uns einen zwingenden Hintergrund haben, was uns manchmal dazu veranlasst, falsche Annahmen darüber zu treffen, was natürlich ist.
Andres F.
Schauen Sie sich die SLT C ++ Bibliothek, die so viel besser lesbar für den Amateur geschrieben werden könnte , um zu sein
Ratsche Freak
@ratchetfreak: Ich denke du meinst STL. Ich denke, dies ist ein sehr gutes Beispiel (und tatsächlich hatte ich dies in meiner Antwort im Hinterkopf). Die Verwendung von Template-Metaprogrammierung ist sehr sinnvoll, wenn Sie ein STL-Programmierer sind, da dadurch die Wiederverwendbarkeit der STL verbessert wird. Und die Leute, die diesen Code pflegen müssen, werden normalerweise auch zur Erstellung von Vorlagen für die Metaprogrammierung verwendet. Wenn Sie die Metaprogrammierung von Vorlagen in einer STL-ähnlichen Weise in Ihrer Standardgeschäftsanwendung verwenden, kann dies leicht zu überkompliziertem, schwer zu wartendem Code führen. Man kann sicherlich (seltene) Fälle finden, in denen TMP auch in der Geschäftsanwendung in Ordnung ist.
Doc Brown
@ DocBrown Ja, Legasthenie trat zur falschen Zeit auf, aber ehrlich gesagt, wenn ich nur die Hälfte der Zeit hätte (und viel mehr Zeit als jetzt), könnte ich viele der Funktionskörper so umschreiben, dass sie viel besser lesbar sind.
Ratschenfreak
7

Ich würde sagen, dass Sie nicht daran gewöhnt sind, wie sie codieren, zumindest ein Teil des Bildes ist. Ich bin in einer ähnlichen Situation wie Sie (ich komme von C # nach F # und arbeite mit Leuten mit Haskell-Hintergrund), und obwohl ich das für eine interessante Erfahrung halte, habe ich Momente, in denen ich meinen Kopf gegen die Wand stoße und a entwirre besonders gewundene punktfreie Funktionskomposition, nur um einen Überblick zu bekommen, was dort vor sich geht. Es ist eine kulturelle Sache.

Ob dieser spezielle Code dem Programm Komplexität verleiht, weiß ich nicht. Einig, dass ein generischer Code selbst komplex sein kann. Aber es ist ein Dienstprogramm, kein Teil der Geschäftslogik. Wenn Sie wissen möchten, ob die Codebasis dadurch komplexer oder einfacher wird, müssen Sie sich vorstellen, wie sie ohne diesen Code aussehen müsste. Bei solchen generischen Konstrukten ist es häufig der Fall, dass sie selbst komplex sind, aber es ist eine Komplexität, die Sie auf einen einzelnen Bildschirm anpassen können. Gleichzeitig vereinfachen sie die gesamte Codebasis ein gutes Stück. Dies ist insbesondere bei Monaden der Fall.

Andererseits kann es sich auch um "Kunst um der Kunst willen" handeln, wie @Doc Brown vorschlägt. Kann es auch nicht ausschließen.

scrwtp
quelle
5

Ich würde argumentieren, dass funktionale Programmierung im Allgemeinen die Komplexität reduziert, indem sie den veränderlichen Zustand eliminiert, wodurch die Anzahl der Fälle reduziert wird, die berücksichtigt werden müssen, wenn versucht wird, die Funktionsweise eines Codeabschnitts zu verstehen.

Die funktionale Programmierung ermöglicht jedoch höhere Abstraktionsgrade, und obwohl hoch abstrakter Code äußerst nützlich sein kann, kann er auch schwer zu verstehen sein, da er per definitionem von dem Kontext getrennt ist, den Sie normalerweise als Leitfaden für Ihr Verständnis verwenden würden. Ihr Kommentar "Sie alle haben eine klare Bedeutung und einen klaren Zweck" zu Geschäftsobjekten ist zweifellos wahr, spiegelt jedoch die Tatsache wider, dass diese Logik sehr spezifisch für ein Bedürfnis und einen Kontext ist, die Sie bereits verstehen. Die Existenz eines Konstrukts wie Monad ermöglicht es Ihnen, mit geringem Aufwand etwas sehr Nützliches zu erstellen, aber das Web ist übersät mit Seiten, die versuchen zu erklären, was eine Monad ist. Das ist Abstraktion für dich.

Außerdem wurde Scalaz von Leuten geschrieben, die schon lange FP gegessen und geatmet hatten. Sie wollten die Funktionalität von Haskell für Scala verfügbar machen. Dabei machten sie keinen Versuch, pädagogisch zu sein. Scalaz bedient sich eines Wortschatzes und Stils, der den Autoren klar und direkt erscheint, den Uneingeweihten jedoch fremd ist. Methoden, die für den Rest von uns rätselhaft sind, schienen den Autoren angesichts ihres Haskell-Hintergrunds so offensichtlich, dass sie nicht einmal einen Kommentar rechtfertigten.

Darüber hinaus weist Scala als funktionale Programmiersprache einige Mängel auf (teilweise, weil die JVM Mängel aufweist), die die Scalaz-Autoren in einigen Fällen gezwungen haben, hässlicheren Code zu schreiben. Zum Beispiel erzwingt das Fehlen einer generellen Tail-Call-Eliminierung die Verwendung von Trampolinen in einigen Codes, und das Fehlen eines "freundlichen Systems" kann Typensignaturen erschweren.

Und schließlich nutzt Scalaz sich selbst sehr gut aus. Das könnte man sich als Zeichen seiner Macht vorstellen, aber für den Uneingeweihten kann es die Quelle zu einem Rätsel machen - jeder zufällige Code, den Sie ansehen, wird wahrscheinlich etwas anderes gebrauchen, das Ihnen fremd vorkommt.

Halte durch. Und das könnte helfen.

AmigoNico
quelle
-4

Fügt es dem Programm Komplexität hinzu, oder ist es nur so, dass Sie nicht an diese Art der Programmierung gewöhnt sind?

Warum denken Sie, sind diese Möglichkeiten nicht dasselbe?

Gut geschriebener Code kann von Personen gelesen werden, die mit der jeweiligen Programmiersprache nicht vertraut sind. Einige Sprachen (BASIC, Pascal usw.) können von Schulkindern gelesen und verstanden werden, die noch nie zuvor eine Programmiersprache gesehen haben.

Wenn jemand, der Erfahrung mit anderen Sprachen und Erfahrung mit Scala hat (und von dem ich annehme, dass er mindestens eine Woche mit Scalaz gearbeitet hat und Kollegen hat, die die schwierigeren Dinge erklären), immer noch verwirrt ist; dann ist das ein Beweis dafür, dass es die Komplexität erhöht hat.

Brendan
quelle
11
Dies ist einfach nicht wahr:"Well written code can be read by people who aren't familiar with the specific programming language."
Andres F.
@Andres: Es ist wahr ... bis zu einem gewissen Punkt. Durch gut geschriebenen Code wird die Geschäftslogik von den Implementierungsdetails getrennt, und die Geschäftslogik sollte lesbar sein, da das meiste, was sie tut, einfache Aufrufe an benannte Hilfsfunktionen ist. Diese Helfer können natürlich alle Arten von Sprachfunktionen verwenden und benötigen umfangreiche Erfahrung mit der Sprache und den Bibliotheken, um diese zu verstehen.
Ben Voigt
4
Ich glaube , die folgende ist idiomatische APL: x[⍋x←6?40]. Was glaubst du, was es tut? Ich hätte es sicher nicht gewusst…
bdesham
3
@Brendan Nur innerhalb desselben Paradigmas (und selbst dann manchmal nicht). Zum Beispiel sind Prolog, Java und APL so unterschiedlich, dass ich behaupten würde, wenn Sie nur eine dieser Sprachen (und keine anderen Sprachen) kennen, können Sie die beiden anderen Sprachen nicht lesen, egal wie gut Sie die erste kennen. (Ernsthaft, in Bdeshams Beispiel, wie zum Teufel soll man "Weihnachtsbaum" interpretieren, wenn man keine APL kennt?)
Izkata
1
Brendan, deine Definition von gut geschrieben ist nicht Standard. Gut geschrieben ist immer relativ zur Sprache und ihrer Gemeinschaft. Ein Programm in Sprache X ist gut geschrieben, wenn es nicht fehlerhaft, effizient und klar ist ... für das gegebene Publikum! Dies gilt übrigens für die Schriftsprache im Allgemeinen: Kennen Sie immer Ihr Publikum. Was für eine wissenschaftliche Arbeit geeignet ist, ist wahrscheinlich nicht für eine E-Mail an Ihre Mutter geeignet.
Andres F.