warum foldLeft anstelle der prozeduralen Version verwenden?

7

Wenn man also diese Frage liest, wurde das stattdessen darauf hingewiesen des Verfahrenscodes:

%Vor%

Sie könnten den folgenden Funktionscode schreiben:

%Vor%

Ich würde fast sicher die erste Version schreiben, weil Programmierer, die mit prozeduralen oder funktionalen Stilen vertraut sind, sie leicht lesen und verstehen können, während nur Programmierer, die mit funktionalem Stil vertraut sind, die zweite Version leicht lesen und verstehen können.

Aber wenn man die Lesbarkeit für den Moment beiseite legt, gibt es etwas, das foldLeft zu einer besseren Wahl macht als die prozedurale Version? Ich hätte gedacht, es wäre effizienter, aber es stellt sich heraus, dass die Implementierung von FoldLeft ist eigentlich nur der obige Verfahrenscode. Also ist es nur eine Stilwahl, oder gibt es einen guten Grund, die eine oder andere Version zu verwenden?

Bearbeiten: Nur um klar zu sein, ich frage nicht nach anderen Funktionen, nur foldLeft . Ich bin vollkommen zufrieden mit der Verwendung von foreach , map , filter usw., die alle auf for-comprehensions gut abbilden.

Antwort: Hier gibt es wirklich zwei gute Antworten (zur Verfügung gestellt von delnan und Dave Griffith ) obwohl ich nur eins akzeptieren konnte:

  • Verwenden Sie foldLeft , da zusätzliche Optimierungen, z. mit einer while-Schleife, die schneller ist als eine for-Schleife.
  • Verwenden Sie fold , wenn es zu regulären Sammlungen hinzugefügt wird, da dies den Übergang zu parallelen Sammlungen trivial macht.
Steve 28.03.2011, 14:10
quelle

4 Antworten

16

Es ist kürzer und klarer - ja, Sie müssen wissen, was eine Falte ist, um es zu verstehen, aber wenn Sie in einer Sprache programmieren, die zu 50% funktionsfähig ist, sollten Sie diese grundlegenden Bausteine ​​sowieso kennen. Eine Falte ist genau das, was der prozedurale Code tut (wiederholtes Anwenden einer Operation), aber er erhält einen Namen und wird verallgemeinert. Und während es nur ein kleines Rad ist, erfinden Sie es neu, aber es ist immer noch eine Neuerfindung des Rades.

Und falls die Implementierung von foldLeft jemals einen speziellen Vorteil erhalten sollte - sagen wir, zusätzliche Optimierungen - erhalten Sie das kostenlos, ohne unzählige Methoden zu aktualisieren.

    
delnan 28.03.2011, 14:19
quelle
9

Abgesehen von der Abneigung gegen veränderliche Variablen (selbst veränderliche Einheimische) ist der Grund für die Verwendung der Faltung in diesem Fall die Klarheit, mit gelegentlicher Kürze. Der größte Teil der Wortigkeit der Falzversion liegt darin, dass Sie eine explizite Funktionsdefinition mit einer Destrukturierungsbindung verwenden müssen. Wenn jedes Element in der Liste genau einmal in der Faltungsoperation verwendet wird (ein häufiger Fall), kann dies vereinfacht werden, um die Kurzform zu verwenden. Also die klassische Definition der Summe einer Zahlensammlung.

%Vor%

ist viel einfacher und kürzer als jedes äquivalente Imperativkonstrukt.

Ein zusätzlicher Grund für die Verwendung funktioneller Auflistungsvorgänge, der in diesem Fall nicht direkt anwendbar ist, besteht darin, die Verwendung paralleler Auflistungsvorgänge zu ermöglichen, wenn dies für die Leistung erforderlich ist. Falten können nicht parallelisiert werden, aber oft können Faltungsoperationen in kommutativ-assoziative Reduktionsoperationen umgewandelt werden, und diese können parallelisiert werden. Mit Scala 2.9 kann es manchmal so einfach sein, etwas von nichtparallelen funktionalen zu parallelen Funktionen mit mehreren Prozessorkernen zu ändern, indem Sie .par auf die Sammlung ablegen, auf der Sie parallele Operationen ausführen möchten.

    
Dave Griffith 28.03.2011 14:35
quelle
7

Ein Wort, das ich hier noch nicht erwähnt habe, ist deklarativ :

>
  

Deklarative Programmierung ist oft definiert als jede Art von Programmierung, die nicht zwingend ist. Es gibt eine Reihe anderer gebräuchlicher Definitionen, die versuchen, dem Begriff eine andere Definition zu geben, als ihn einfach der imperativen Programmierung gegenüberzustellen. Zum Beispiel:

     
  • Ein Programm, das beschreibt, welche Berechnungen durchgeführt werden sollten und nicht wie um es zu berechnen
  •   
  • Jede Programmiersprache, die keine Nebenwirkungen hat (oder genauer gesagt, ist referenziell transparent)
  •   
  • Eine Sprache mit einer klaren Übereinstimmung mit der mathematischen Logik.
  •   

Diese Definitionen überschneiden sich erheblich.

Funktionen höherer Ordnung (HOFs) sind ein Schlüsselermöglicher für die Deklarativität, da wir nur das was spezifizieren (zB "benutze diese Sammlung von Werten, multipliziere jeden Wert mit 2, summiere das Ergebnis") und nicht das wie (zB einen Akkumulator initialisieren, mit einer for-Schleife iterieren, Werte aus der Sammlung extrahieren, zum Akkumulator addieren ...).

Vergleichen Sie Folgendes:

%Vor%

Beachten Sie, dass unser erstes Beispiel, sumDoubled1 , bereits deklarativer ist als C / C ++ / Java & lt; 5 für Schleifen, da wir die Iterationsstatus- und Terminierungslogik nicht mikromantieren mussten. aber wir sind immer noch anfällig für einzelne Fehler.

Als nächstes, in sumDoubled2 , befinden wir uns im Grunde auf der Ebene von Java & gt; = 5. Es gibt immer noch ein paar Dinge, die schiefgehen können, aber wir werden ziemlich gut darin, diese Codeform zu lesen, daher sind Fehler ziemlich unwahrscheinlich. Allerdings , vergessen Sie nicht, dass ein Muster, das in einem Spielzeugbeispiel trivial ist, nicht immer so lesbar ist, wenn es auf Produktionscode skaliert wird!

Mit sumDoubled3 , für didaktische Zwecke entzogen, und sumDoubled4 , die idiomatische Scala-Version, die Iteration, die Initialisierung, die Wertextraktion und die Auswahl des Rückgabewerts sind alle weg.

Sicher, es braucht Zeit, um die funktionalen Versionen zu lesen, aber wir haben unsere Möglichkeiten, Fehler zu machen, drastisch ausgeschlossen. Die "Geschäftslogik" ist deutlich markiert, und die Installation wird aus dem gleichen Menü gewählt, aus dem auch alle anderen lesen.

    
Alex Cruise 28.03.2011 21:01
quelle
2

Es ist erwähnenswert, dass es eine andere Möglichkeit gibt, foldLeft aufzurufen, die folgende Vorteile bietet:

  • Die Möglichkeit, (fast) jedes Unicode-Symbol in einem Bezeichner zu verwenden
  • Die Funktion, dass, wenn ein Methodenname mit einem Doppelpunkt : endet und Infix heißt, das Ziel und der Parameter gewechselt werden

Für mich ist diese Version viel übersichtlicher, weil ich sehen kann, dass ich den expr Wert in die replacements Sammlung falte

%Vor%     
oxbow_lakes 29.03.2011 10:38
quelle

Tags und Links