Warum sind Märchen und Ramda so unterschiedlich?

96

Ich lerne Javascript FP, indem ich DrBooleans Buch lese .

Ich suchte nach einer funktionalen Programmierbibliothek. Ich habe Ramda und Folktale gefunden. Beide behaupten, eine funktionale Programmierbibliothek zu sein.

Aber sie sind so unterschiedlich:

  • Ramda scheint Utility-Funktionen für den Umgang mit Listen zu enthalten: Map, Reduce, Filter und reine Funktionen: Curry, Compose. Es enthält nichts, was mit Monade, Funktor zu tun hätte.

  • Folktale enthält jedoch kein Dienstprogramm für Listen oder Funktionen. Es scheint einige algebraische Strukturen in Javascript wie Monade zu implementieren: Vielleicht, Aufgabe ...

Eigentlich habe ich mehr Bibliotheken gefunden, sie scheinen alle in die beiden Kategorien zu fallen. Unterstrich und Lodash sind wie Ramda. Fantasy-Land, Pointfree-Fantasy sind wie Märchen.

Können diese sehr unterschiedlichen Bibliotheken beide als funktional bezeichnet werden , und wenn ja, was macht jede Bibliothek zu einer funktionalen Bibliothek?

Aaron Shen
quelle
1
Verwenden Sie, was Ihren Bedürfnissen und Ihrem Stil entspricht und gut dokumentiert ist
charlietfl
1
Ich habe festgestellt, dass es wirklich drei allgemein beabsichtigte Bedeutungen für "funktionale Programmierung" gibt, insbesondere in JS. 1. Verwenden von reinen Funktionen höherer Ordnung für Mengen wie Arrays., Bsp. [1,2,3].map(fnSquare).reduce(fnSum)2. weitgehend akademische Y-Kombinator-ähnliche Strukturen "look ma no var ". 3. Verwenden Function.prototype, um das Verhalten anderer Funktionen zu ändern, wievar isMissingID=fnContains.partial("id").negate();
Dandavis
10
Ein Ramda-Autor hier: Ramda ist eine relativ einfache Utility-Bibliothek. Es ist beabsichtigt, einen bestimmten Funktionsstil in JS zu vereinfachen, insbesondere durch das Erstellen von Funktionen. Ramda funktioniert gut mit der FantasyLand-Spezifikation, einschließlich Implementierungen wie Folktale. Diese Bibliotheken sind für einen etwas anderen Zweck konzipiert. Sie basieren darauf, gängige abstrakte Datentypen zu erkennen und einen konsistenten Zugriff darauf zu ermöglichen: Monoide, Funktoren und Monaden. Ramda wird mit ihnen zusammenarbeiten und hat ein Nebenprojekt, um einige zu erstellen, aber es ist, wie Sie sagen, ein ganz anderer Fokus.
Scott Sauyet
1
@KeithNicholas: Ja, es ist ein Gitter Zimmer
Scott Sauyet
2
Schauen Sie sich auch Sanctuary an - github.com/plaid/sanctuary Dies basiert auf Ramda, deckt aber auch Fantasy-Land-Typen ab.
Arcseldon

Antworten:

179

Funktionsmerkmale

Es gibt keine klare Grenze für die Definition der funktionalen Programmierung oder einer funktionalen Bibliothek. Einige Funktionen funktionaler Sprachen sind in Javascript integriert:

  • Erstklassige Funktionen höherer Ordnung
  • Lambdas / Anonymous-Funktionen mit Verschlüssen

Andere sind in Javascript mit einiger Sorgfalt möglich:

  • Unveränderlichkeit
  • Referentielle Transparenz

Wieder andere sind Teil von ES6 und derzeit teilweise oder vollständig verfügbar:

  • Kompakte, sogar knappe Funktionen
  • Performante Rekursion durch Tail-Call-Optimierung

Und es gibt viele andere, die außerhalb der normalen Reichweite von Javascript liegen:

  • Mustervergleich
  • Faule Bewertung
  • Homoikonizität

Eine Bibliothek kann dann auswählen, welche Arten von Funktionen sie unterstützen möchte, und dennoch vernünftigerweise als "funktional" bezeichnet werden.

Fantasy-Land-Spezifikation

Fantasy-Land ist eine Spezifikation für eine Reihe von Standardtypen, die von der mathematischen Kategorietheorie und der abstrakten Algebra bis zur funktionalen Programmierung portiert sind, wie Monoid , Functor und Monad . Diese Typen sind ziemlich abstrakt und erweitern möglicherweise bekanntere Begriffe. Funktoren sind beispielsweise Container, die mapmit einer Funktion überfahren werden können, so wie ein Array mit mapüberfahren werden kann Array.prototype.map.

Märchen

Folktale ist eine Sammlung von Typen, die verschiedene Teile der Fantasy-Land-Spezifikation implementieren, sowie eine kleine Sammlung von begleitenden Dienstprogrammfunktionen. Diese Typen sind Dinge wie Vielleicht , Entweder , Aufgabe (sehr ähnlich zu dem, was anderswo als Zukunft bezeichnet wird, und ein rechtmäßigerer Cousin eines Versprechens) und Validierung

Folktale ist vielleicht die bekannteste Implementierung der Fantasy-Land-Spezifikation und wird sehr geschätzt. Es gibt jedoch keine endgültige oder Standardimplementierung. Fantasy-Land spezifiziert nur abstrakte Typen, und eine Implementierung muss natürlich solche konkreten Typen erzeugen. Der Anspruch von Folktale, eine funktionale Bibliothek zu sein, ist klar: Es bietet Datentypen, die typischerweise in funktionalen Programmiersprachen zu finden sind und die das funktionale Programmieren wesentlich erleichtern.

Dieses Beispiel aus der Folktale-Dokumentation ( Hinweis : nicht in neueren Versionen der Dokumente) zeigt, wie es verwendet werden kann:

// We load the library by "require"-ing it
var Maybe = require('data.maybe')

// Returns Maybe.Just(x) if some `x` passes the predicate test
// Otherwise returns Maybe.Nothing()
function find(predicate, xs) {
  return xs.reduce(function(result, x) {
    return result.orElse(function() {
      return predicate(x)?    Maybe.Just(x)
      :      /* otherwise */  Maybe.Nothing()
    })
  }, Maybe.Nothing())
}

var numbers = [1, 2, 3, 4, 5]

var anyGreaterThan2 = find(function(a) { return a > 2 }, numbers)
// => Maybe.Just(3)

var anyGreaterThan8 = find(function(a) { return a > 8 }, numbers)
// => Maybe.Nothing

Ramda

Ramda (Haftungsausschluss: Ich bin einer der Autoren) ist eine ganz andere Art von Bibliothek. Es werden keine neuen Typen für Sie bereitgestellt. 1 Stattdessen bietet es Funktionen, die die Bedienung vorhandener Typen erleichtern. Es basiert auf dem Gedanken, kleinere Funktionen zu größeren zusammenzusetzen, mit unveränderlichen Daten zu arbeiten und Nebenwirkungen zu vermeiden.

Ramda arbeitet insbesondere mit Listen, aber auch mit Objekten und manchmal mit Strings. Es delegiert auch viele seiner Aufrufe so, dass es mit Folktale oder anderen Fantasy-Land-Implementierungen zusammenarbeitet. Zum Beispiel mapfunktioniert Ramdas Funktion ähnlich wie die auf Array.prototype, also R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]. Da Folktale's Maybejedoch die Fantasy-Land- FunctorSpezifikation implementiert , die auch die Karte spezifiziert, können Sie auch Ramdas mapdamit verwenden:

R.map(square, Maybe.Just(5)); //=> Maybe.Just(25);
R.map(square, Maybe.Nothing); //=> Maybe.Nothing

Ramdas Anspruch, eine funktionale Bibliothek zu sein, besteht darin, das Erstellen von Funktionen zu vereinfachen, Ihre Daten niemals zu mutieren und nur reine Funktionen zu präsentieren. Typische Verwendung von Ramda wäre der Aufbau komplexerer Funktionen durch Zusammensetzen kleinerer, wie in einem Artikel über die Philosophie von Ramda zu sehen ist

// :: [Comment] -> [Number]  
var userRatingForComments = R.pipe(
    R.pluck('username')      // [Comment] -> [String]
    R.map(R.propOf(users)),  // [String] -> [User]
    R.pluck('rating'),       // [User] -> [Number]
);

Andere Bibliotheken

Eigentlich habe ich mehr Bibliotheken gefunden, sie scheinen alle in die beiden Kategorien zu fallen. Lodash sind Ramda sehr ähnlich. Fantasy-Land, Pointfree-Fantasy sind wie Märchen.

Das ist nicht wirklich genau. Erstens ist Fantasy-Land einfach eine Spezifikation, die Bibliotheken für verschiedene Typen implementieren können. Folktale ist eine von vielen Implementierungen dieser Spezifikation, wahrscheinlich die am besten abgerundete, sicherlich eine der ausgereiftesten. Pointfree-Fantasy und Ramda-Fantasy sind andere, und es gibt noch viele mehr .

Unterstrich und Lodash sind oberflächlich wie Ramda, da sie Grab-Bag-Bibliotheken sind und eine große Anzahl von Funktionen mit viel weniger Zusammenhalt bieten als so etwas wie Folktale. Und selbst die spezifischen Funktionen überschneiden sich häufig mit denen von Ramda. Auf einer tieferen Ebene hat Ramda jedoch ganz andere Bedenken als diese Bibliotheken. Ramda engsten Verwandten sind wahrscheinlich Bibliotheken wie FKIT , Fnuc und Wu.js .

Bilby gehört zu einer eigenen Kategorie und bietet sowohl eine Reihe von Tools wie die von Ramda als auch einige Typen, die mit Fantasy-Land übereinstimmen. (Der Autor von Bilby ist auch der ursprüngliche Autor von Fantasy-Land.)

Ihr Anruf

Alle diese Bibliotheken haben das Recht, als funktional bezeichnet zu werden, obwohl sie sich in ihrem funktionalen Ansatz und dem Grad des funktionalen Engagements stark unterscheiden.

Einige dieser Bibliotheken arbeiten tatsächlich gut zusammen. Ramda sollte gut mit Folktale oder anderen Fantasy-Land-Implementierungen funktionieren. Da sich ihre Bedenken kaum überschneiden, stehen sie wirklich nicht in Konflikt, aber Ramda tut gerade genug, um die Interaktion relativ reibungslos zu gestalten. Dies gilt wahrscheinlich weniger für einige der anderen Kombinationen, die Sie auswählen können, aber die einfachere Funktionssyntax von ES6 kann auch die Integration erleichtern.

Die Wahl der Bibliothek oder sogar Stil der Bibliothek zu verwenden, wird auf Ihrem Projekt und Ihre Vorlieben ab. Es gibt viele gute Optionen, und die Anzahl wächst, und viele von ihnen verbessern sich erheblich. Es ist ein guter Zeitpunkt, um funktionale Programmierung in JS durchzuführen.


1 Nun, es gibt ein Nebenprojekt, eine Ramda-Fantasie , die etwas Ähnliches wie Folktale macht, aber nicht Teil der Kernbibliothek ist .

Scott Sauyet
quelle
1
Wäre es fair zu sagen, dass ES6 mit der Einführung von Yield die Fähigkeit zur verzögerten Bewertung hat? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Marcel Lamothe
8
Nein yieldmacht es einfacher, die von Lazyoder durchgeführten faulen Listenverarbeitungen durchzuführen lz.js. Aber es hilft nicht bei Faulheit auf Sprachniveau. someFunc(a + b)In JS werden zuerst die Werte von hinzugefügt aund bdann das Ergebnis als Parameter an someFunc übergeben. Das Äquivalent in Haskell macht das nicht. Wenn die aufgerufene Funktion diesen Wert niemals verwendet, führt sie niemals die Addition durch. Wenn es irgendwann verwendet wird, wird es als Ausdruck betrachtet, der berechnet wird, bis das Ergebnis benötigt wird. Wenn Sie niemals etwas tun, das es erzwingt (wie E / A), wird die Berechnung niemals tatsächlich durchgeführt.
Scott Sauyet
@ScottSauyet Vielleicht könnten Sie argumentieren, dass "Lazy Evaluation" in irgendeiner Form beispielsweise über ES6-Generatoren verfügbar ist - viele JS-Frameworks haben "Faulheit" -Eigenschaften - RxJs, ImmutableJs usw.
arcseldon
8
Diese Antwort sollte ein Kapitel oder ein Abschnitt in DrBooleans Buch sein. :)
Seth
1
In der Ramda-Dokumentation wird "Liste" in der Regel als Abkürzung für das verwendet, was JS Listen und dichten Arrays am nächsten kommt. Diese haben andere Leistungsmerkmale als reine Listen und natürlich eine etwas andere API, aber sie können für fast dieselben Zwecke verwendet werden, und sie sind der nächste native Typ (siehe jedoch github.com/funkia/list ), der Ramda zur Verfügung steht API, die konzeptionell mit reinen Listen arbeiten möchte. Ich würde den Punkt der nicht wahren Arrays argumentieren, da Arrays im C-Stil nicht kanonischer sind als JS und keine wirklich nahe an mathematischen Arrays, aber das ist ein kleiner Punkt.
Scott Sauyet