Erklärung der Kombinatoren für den Arbeiter

93

Was ist ein Kombinator?

Ist es "eine Funktion oder Definition ohne freie Variablen" (wie in SO definiert)?

Oder wie wäre es damit: Laut John Hughes in seinem bekannten Artikel über Pfeile ist "ein Kombinator eine Funktion, die Programmfragmente aus Programmfragmenten erstellt" , was vorteilhaft ist, weil "... der Programmierer, der Kombinatoren verwendet, einen Großteil der gewünschten Konstrukteure konstruiert automatisch programmieren, anstatt jedes Detail von Hand zu schreiben ". Er fährt fort zu sagen , dass mapund filtersind zwei typische Beispiele für solche combinators.

Einige Kombinatoren, die der ersten Definition entsprechen:

Einige Kombinatoren, die der zweiten Definition entsprechen:

  • Karte
  • Filter
  • falten / reduzieren (vermutlich)
  • eine von >> =, komponieren, fmap ?????

Ich bin nicht an der ersten Definition interessiert - diese würden mir nicht helfen, ein echtes Programm zu schreiben (+1, wenn Sie mich davon überzeugen, dass ich falsch liege). Bitte helfen Sie mir, die zweite Definition zu verstehen . Ich denke, Map, Filter und Reduce sind nützlich: Sie ermöglichen es mir, auf einer höheren Ebene zu programmieren - weniger Fehler, kürzerer und klarerer Code. Hier sind einige meiner spezifischen Fragen zu Kombinatoren:

  1. Was sind weitere Beispiele für Kombinatoren wie Map, Filter?
  2. Welche Kombinatoren implementieren Programmiersprachen häufig?
  3. Wie können Kombinatoren mir helfen, eine bessere API zu entwerfen?
  4. Wie entwerfe ich effektive Kombinatoren?
  5. Was ähneln Kombinatoren in einer nicht funktionierenden Sprache (z. B. Java) oder was verwenden diese Sprachen anstelle von Kombinatoren?

Aktualisieren

Dank @CA McCann habe ich jetzt ein etwas besseres Verständnis für Kombinatoren. Aber eine Frage ist für mich immer noch ein Knackpunkt:

Was ist der Unterschied zwischen einem Funktionsprogramm, das mit und ohne starken Einsatz von Kombinatoren geschrieben wurde?

Ich vermute, die Antwort ist, dass die kombinatorlastige Version kürzer, klarer und allgemeiner ist, aber ich würde mich über eine eingehendere Diskussion freuen, wenn dies möglich ist.

Ich suche auch nach mehr Beispielen und Erklärungen für komplexe Kombinatoren (dh komplexer als fold) in gängigen Programmiersprachen.

Matt Fenwick
quelle
4
Ich betrachte Map / Filter / Fold -Funktionen höherer Ordnung und benutze sie ständig. Ich habe immer noch keine Ahnung, was ein Kombinator ist.
1
@pst - Ich hätte vor 5 Tagen zugestimmt, aber jetzt kann ich nicht mit John Hughes
Matt Fenwick

Antworten:

93

Ich bin nicht an der ersten Definition interessiert - diese würden mir nicht helfen, ein echtes Programm zu schreiben (+1, wenn Sie mich davon überzeugen, dass ich falsch liege). Bitte helfen Sie mir, die zweite Definition zu verstehen. Ich denke, Map, Filter und Reduce sind nützlich: Sie ermöglichen es mir, auf einer höheren Ebene zu programmieren - weniger Fehler, kürzerer und klarerer Code.

Die beiden Definitionen sind im Grunde dasselbe. Die erste basiert auf der formalen Definition und die Beispiele, die Sie geben, sind primitive Kombinatoren - die kleinstmöglichen Bausteine. Sie können Ihnen helfen, ein echtes Programm zu schreiben, indem Sie mit ihnen ausgefeiltere Kombinatoren bauen können. Stellen Sie sich Kombinatoren wie S und K als die Maschinensprache eines hypothetischen "kombinatorischen Computers" vor. Tatsächliche Computer funktionieren natürlich nicht so. In der Praxis werden Operationen auf höherer Ebene normalerweise auf andere Weise hinter den Kulissen implementiert, aber die konzeptionelle Grundlage ist immer noch ein nützliches Werkzeug, um die Bedeutung dieser übergeordneten Ebenen zu verstehen Operationen.

Die zweite Definition, die Sie geben, ist informeller und bezieht sich auf die Verwendung komplexerer Kombinatoren in Form von Funktionen höherer Ordnung, die andere Funktionen auf verschiedene Weise kombinieren. Beachten Sie, dass, wenn die Grundbausteine ​​die oben genannten primitiven Kombinatoren sind, alles , was daraus aufgebaut ist, eine Funktion höherer Ordnung und auch ein Kombinator ist. In einer Sprache, in der andere Grundelemente existieren, wird jedoch zwischen Dingen unterschieden, die Funktionen sind oder nicht. In diesem Fall wird ein Kombinator normalerweise als eine Funktion definiert, die andere Funktionen allgemein manipuliert, anstatt mit Nichtfunktionen zu arbeiten Dinge direkt funktionieren.

Was sind weitere Beispiele für Kombinatoren wie Map, Filter?

Viel zu viele, um sie aufzulisten! Beide wandeln eine Funktion, die das Verhalten eines einzelnen Werts beschreibt, in eine Funktion um, die das Verhalten einer gesamten Sammlung beschreibt. Sie können auch Funktionen haben, die nur andere Funktionen transformieren , z. B. das Ende-zu-Ende-Erstellen oder das Teilen und Rekombinieren von Argumenten. Sie können Kombinatoren haben, die Einzelschrittoperationen in rekursive Operationen umwandeln, die Sammlungen erzeugen oder verbrauchen. Oder wirklich alle möglichen anderen Dinge.

Welche Kombinatoren implementieren Programmiersprachen häufig?

Das wird ziemlich unterschiedlich sein. Es gibt relativ wenige vollständig generische Kombinatoren - meistens die oben genannten primitiven -, so dass Kombinatoren in den meisten Fällen ein gewisses Bewusstsein dafür haben, welche Datenstrukturen verwendet werden (selbst wenn diese Datenstrukturen ohnehin aus anderen Kombinatoren aufgebaut sind), in denen In diesem Fall gibt es normalerweise eine Handvoll "vollständig generischer" Kombinatoren und dann, was auch immer verschiedene spezielle Formen sind, für die sich jemand entschieden hat. Es gibt eine lächerliche Anzahl von Fällen, in denen (entsprechend verallgemeinerte Versionen von) Zuordnen, Falten und Entfalten ausreichen, um fast alles zu tun, was Sie möchten.

Wie können Kombinatoren mir helfen, eine bessere API zu entwerfen?

Genau wie Sie sagten, indem Sie in Bezug auf Operationen auf hoher Ebene und die Art und Weise, wie diese interagieren, anstelle von Details auf niedriger Ebene denken.

Denken Sie an die Beliebtheit von "for each" -Stilschleifen über Sammlungen, mit denen Sie die Details der Aufzählung einer Sammlung abstrahieren können. Dies sind in den meisten Fällen nur Map / Fold-Operationen. Wenn Sie einen Kombinator (anstelle einer integrierten Syntax) verwenden, können Sie beispielsweise zwei vorhandene Schleifen verwenden und diese auf mehrere Arten direkt kombinieren - ineinander verschachteln. Tun Sie dies nacheinander und so weiter - indem Sie einfach einen Kombinator anwenden, anstatt eine ganze Menge Code herumzujonglieren.

Wie entwerfe ich effektive Kombinatoren?

Überlegen Sie sich zunächst, welche Vorgänge für die von Ihrem Programm verwendeten Daten sinnvoll sind. Überlegen Sie sich dann, wie diese Operationen auf generische Weise sinnvoll kombiniert werden können und wie Operationen in kleinere Teile zerlegt werden können, die wieder miteinander verbunden sind. Die Hauptsache ist, mit Transformationen und Operationen zu arbeiten , nicht mit direkten Aktionen . Wenn Sie eine Funktion haben, die nur einige komplizierte Funktionen auf undurchsichtige Weise ausführt und nur ein vorverdautes Ergebnis ausspuckt, können Sie damit nicht viel tun. Überlassen Sie die endgültigen Ergebnisse dem Code, der die Kombinatoren verwendet - Sie möchten Dinge, die Sie von Punkt A nach Punkt B führen, nicht Dinge, die den Beginn oder das Ende eines Prozesses erwarten.

Was ähneln Kombinatoren in einer nicht funktionierenden Sprache (z. B. Java) oder was verwenden diese Sprachen anstelle von Kombinatoren?

Ahahahaha. Lustig sollte man fragen, denn Objekte sind in erster Linie Dinge höherer Ordnung - sie haben einige Daten, aber sie führen auch eine Reihe von Operationen mit sich, und vieles, was ein gutes OOP-Design ausmacht, läuft darauf hinaus, dass Objekte "sollten" wirken normalerweise wie Kombinatoren, nicht wie Datenstrukturen ".

Die wahrscheinlich beste Antwort hier ist also, dass sie anstelle kombinatorähnlicher Dinge Klassen mit vielen Getter- und Setter-Methoden oder öffentlichen Feldern verwenden und eine Logik, die hauptsächlich darin besteht, eine undurchsichtige, vordefinierte Aktion auszuführen.

CA McCann
quelle
Gute Antwort! Mal sehen, ob ich es verstehe - Kombinatoren sind nichts Besonderes, sondern ein wesentlicher Bestandteil beim Aufbau eines wartbaren Softwaresystems. Ich versuche immer noch, Hughes 'Aussage "Programmfragmente" im Kontext Ihres Beitrags zu verdauen.
Matt Fenwick
@Matt Fenwick: Ich bin mir ziemlich sicher, dass er nur "Programmfragmente" verwendet, um die Art von Transformationen / Operationen zu bezeichnen, von denen ich spreche, insbesondere wenn es sich um "Pfeile" handelt, die diesen Ansatz noch stärker betonen. Ich würde auch nicht sagen, dass es darum geht, wartbare Systeme genau zu bauen - mehr darum, Systeme zu bauen, die hochmodular und auf besondere Weise entkoppelt sind , mit den damit verbundenen Vorteilen.
CA McCann
Kennen Sie gute Ressourcen, um sich über den praktischen Einsatz von Kombinatoren zu informieren? Vielen Dank!
Matt Fenwick
@ Matt Fenwick: Nichts Spezielles auf den ersten , sorry. Es ist jedoch in der Regel ein natürlicher Ansatz für Programme, die in einem sehr funktionalen Stil geschrieben sind. Verbringen Sie also nur einige Zeit mit Sprachen, die dies stark fördern (z. B. Haskell oder Clojure), und schauen Sie sich an, wie sauber und idiomatisch Code in dieser Sprache geschrieben ist ist ein ziemlich guter Weg, um ein Gefühl für den Stil zu bekommen.
CA McCann