it-swarm-eu.dev

Was ist der Zweck von Pfeilen?

Ich lerne funktionale Programmierung mit Haskell und versuche, Konzepte zu erfassen, indem ich zuerst verstehe, warum ich sie brauche.

Ich möchte das Ziel von Pfeilen in funktionalen Programmiersprachen kennen. Welches Problem lösen sie? Ich habe http://en.wikibooks.org/wiki/Haskell/Understanding_arrows und http: // www überprüft .cse.chalmers.se/~ rjmh/afp-arrows.pdf . Ich verstehe nur, dass sie zur Beschreibung von Diagrammen für Berechnungen verwendet werden und eine einfachere punktfreie Codierung ermöglichen.

Der Artikel geht davon aus, dass der punktfreie Stil im Allgemeinen leichter zu verstehen und zu schreiben ist. Das scheint mir ziemlich subjektiv zu sein. In einem anderen Artikel ( http://en.wikibooks.org/wiki/Haskell/StephensArrowTutorial#Hangman:_Main_program ) wird jedoch ein Henker-Spiel implementiert Ich kann nicht sehen, wie Pfeile diese Implementierung natürlich machen.

Ich konnte viele Artikel finden, die das Konzept beschreiben, aber nichts über die Motivation.

Was fehlt mir?

63
Simon Bergot

Mir ist klar, dass ich zu spät zur Party komme, aber Sie haben hier zwei theoretische Antworten erhalten, und ich wollte eine praktische Alternative zum Kauen bieten. Ich komme als verwandter Haskell-Noob dazu, der dennoch kürzlich für ein Projekt, an dem ich gerade arbeite, durch das Thema Pfeile gewaltsam marschiert wurde.

Erstens können Sie die meisten Probleme in Haskell produktiv lösen, ohne nach Pfeilen zu greifen. Einige bemerkenswerte Haskeller mögen sie wirklich nicht und benutzen sie nicht (siehe hier , hier und hier für mehr dazu). Wenn Sie sich also sagen: "Hey, ich brauche diese nicht", verstehen Sie, dass Sie möglicherweise wirklich Recht haben.

Was mich an Arrows am meisten frustrierte, als ich sie zum ersten Mal lernte, war, wie die Tutorials zu diesem Thema unweigerlich nach der Analogie der Schaltkreise griffen. Wenn Sie sich den Pfeilcode ansehen - zumindest die gezuckerte Sorte -, ähnelt er nichts so sehr wie einer Hardware-Definitionssprache. Ihre Eingänge sind rechts und Ihre Ausgänge links ausgerichtet, und wenn Sie nicht alle richtig verkabeln, werden sie einfach nicht ausgelöst. Ich dachte mir: Wirklich? Sind wir hier gelandet? Haben wir eine Sprache geschaffen, die so vollständig ist, dass sie wieder aus Kupferdrähten und Lot besteht?

Die richtige Antwort darauf lautet, soweit ich feststellen konnte: Eigentlich ja. Der derzeitige Killer-Anwendungsfall für Arrows ist FRP (denken Sie an Yampa, Spiele, Musik und reaktive Systeme im Allgemeinen). Das Problem, mit dem FRP konfrontiert ist, ist weitgehend das gleiche, mit dem alle anderen synchronen Nachrichtensysteme konfrontiert sind: Wie verdrahtet man einen kontinuierlichen Strom von Eingaben in einen kontinuierlichen Strom von Ausgaben, ohne relevante Informationen fallen zu lassen oder Lecks zu verursachen? Sie können die Streams als Listen modellieren - mehrere neuere FRP-Systeme verwenden diesen Ansatz -, aber wenn Sie viele Eingabelisten haben, ist die Verwaltung fast unmöglich. Sie müssen sich vom Strom isolieren.

Was Pfeile in FRP-Systemen zulassen, ist die Zusammensetzung von Funktionen in einem Netzwerk, während gleichzeitig jeglicher Verweis auf die zugrunde liegenden Werte, die von diesen Funktionen übergeben werden, vollständig abstrahiert wird. Wenn Sie FP noch nicht kennen, kann dies zunächst verwirrend und dann umwerfend sein, wenn Sie die Auswirkungen auf FP aufgegriffen haben. Sie haben erst kürzlich die Idee aufgegriffen, dass Funktionen abstrahiert werden können und wie man eine Liste wie [(*), (+), (-)] als vom Typ [(a -> a -> a)] versteht. Mit Pfeilen können Sie die Abstraktion eine Ebene weiter verschieben.

Diese zusätzliche Fähigkeit zur Abstraktion birgt ihre eigenen Gefahren. Zum einen kann es GHC in Eckfälle bringen, in denen es nicht weiß, was es von Ihren Typannahmen halten soll. Sie müssen bereit sein, auf Typebene zu denken - dies ist eine hervorragende Gelegenheit, um mehr über Arten und RankNTypes und andere solche Themen zu erfahren.

Es gibt auch eine Reihe von Beispielen für "Stupid Arrow Stunts", bei denen der Codierer nach einem Pfeilkombinator greift, nur weil er oder sie einen ordentlichen Trick mit Tupeln vorführen möchte. (Hier ist mein eigener trivialer Beitrag zum Wahnsinn .) Zögern Sie nicht, solche Hot-Dogging zu ignorieren, wenn Sie in freier Wildbahn darauf stoßen.

HINWEIS: Wie ich oben erwähnt habe, bin ich ein relativer Noob. Wenn ich oben falsche Vorstellungen gemacht habe, können Sie mich gerne korrigieren.

44
rtperson

Dies ist eine Art "weiche" Antwort, und ich bin mir nicht sicher, ob eine Referenz dies tatsächlich auf diese Weise angibt, aber so bin ich zu Pfeilen gekommen:

Ein Pfeiltyp A b c Ist im Grunde eine Funktion b -> c, Aber mit mehr Struktur, so wie ein monadischer Wert M a Mehr Struktur hat als ein einfaches altes a .

Was diese zusätzliche Struktur zufällig ist, hängt von der bestimmten Pfeilinstanz ab, über die Sie sprechen. Genau wie bei Monaden haben IO a Und Maybe a Jeweils unterschiedliche Zusatzstrukturen.

Die Sache, die Sie mit Monaden bekommen, ist die Unfähigkeit, von einem M a Zu einem a zu wechseln. Dies mag wie eine Einschränkung erscheinen, ist aber tatsächlich eine Funktion: Das Typsystem schützt Sie davor, einen monadischen Wert in einen einfachen alten Wert umzuwandeln. Sie können den Wert nur verwenden, indem Sie über >>= Oder die primitiven Operationen der jeweiligen Monadeninstanz an der Monade teilnehmen.

Ebenso ist das, was Sie von A b c Erhalten, die Unfähigkeit, eine neue b-konsumierende c-produzierende "Funktion" zu konstruieren. Der Pfeil schützt Sie davor, das b zu verbrauchen und ein c zu erstellen, außer indem Sie an den verschiedenen Pfeilkombinatoren teilnehmen oder die primitiven Operationen der jeweiligen Pfeilinstanz verwenden.

Zum Beispiel sind die Signalfunktionen in Yampa ungefähr (Time -> a) -> (Time -> b), Aber zusätzlich müssen sie eine bestimmte Kausalität Einschränkung beachten: Die Ausgabe zum Zeitpunkt t wird durch die vergangenen Werte bestimmt des Eingangssignals: Sie können nicht in die Zukunft schauen. Sie programmieren also nicht mit (Time -> a) -> (Time -> b), Sondern mit SF a b Und bauen Ihre Signalfunktionen aus Grundelementen auf. Es kommt also vor, dass sich SF a b Sehr ähnlich wie eine Funktion verhält, sodass diese gemeinsame Struktur als "Pfeil" bezeichnet wird.

30
Lambdageek

Ich stelle mir Pfeile wie Monaden und Funktoren gerne so vor, dass der Programmierer exotische Kompositionen von Funktionen erstellen kann.

Ohne Monaden oder Pfeile (und Funktoren) beschränkt sich die Zusammensetzung von Funktionen in einer funktionalen Sprache darauf, eine Funktion auf das Ergebnis einer anderen Funktion anzuwenden. Mit Monaden und Funktoren können Sie zwei Funktionen definieren und dann separaten wiederverwendbaren Code schreiben, der angibt, wie diese Funktionen im Kontext der jeweiligen Monade miteinander und mit den an sie übergebenen Daten interagieren. Dieser Code wird in den Bindecode der Monade eingefügt. Eine Monade ist also eine einzige Ansicht, nur ein Container für wiederverwendbaren Bindecode. Funktionen setzen sich im Kontext einer Monade anders zusammen als in einer anderen Monade.

Ein einfaches Beispiel ist die Vielleicht-Monade, bei der die Bindefunktion Code enthält. Wenn also eine Funktion A mit einer Funktion B innerhalb einer Vielleicht-Monade zusammengesetzt ist und B ein Nichts erzeugt, stellt der Bindecode sicher, dass die Zusammensetzung der Zwei Funktionen geben ein Nothing aus, ohne sich die Mühe zu machen, A auf den von B ausgehenden Nothing-Wert anzuwenden. Wenn es keine Monade gäbe, müsste der Programmierer Code in A schreiben, um auf eine Nothing-Eingabe zu testen.

Monaden bedeuten auch, dass der Programmierer die für jede Funktion erforderlichen Parameter nicht explizit in den Quellcode eingeben muss - die Bindefunktion übernimmt die Parameterübergabe. Bei Verwendung von Monaden kann der Quellcode also eher wie eine statische Kette von Funktionsnamen aussehen, als ob Funktion A Funktion B mit den Parametern C und D "aufruft" - der Code fühlt sich eher wie eine elektronische Schaltung als wie eine an bewegliche Maschine - funktionaler als zwingend erforderlich.

Pfeile verbinden auch Funktionen mit einer Bindefunktion, die wiederverwendbare Funktionen bereitstellen und Parameter ausblenden. Pfeile können jedoch selbst miteinander verbunden und zusammengesetzt werden und optional zur Laufzeit Daten an andere Pfeile weiterleiten. Jetzt können Sie Daten auf zwei Pfade von Pfeilen anwenden, die "unterschiedliche Dinge" mit den Daten tun, und das Ergebnis wieder zusammensetzen. Oder Sie können auswählen, an welchen Zweig von Pfeilen die Daten übergeben werden sollen, abhängig von einem bestimmten Wert in den Daten. Der resultierende Code ähnelt noch mehr einer elektronischen Schaltung mit Schaltern, Verzögerungen, Integration usw. Das Programm sieht sehr statisch aus, und Sie sollten nicht in der Lage sein, viel Manipulation von Daten zu sehen. Es gibt immer weniger Parameter, über die man nachdenken muss, und es muss weniger darüber nachgedacht werden, welche Werte Parameter annehmen können oder nicht.

Das Schreiben eines Arrowized-Programms umfasst hauptsächlich das Auswählen von Pfeilen wie Splittern, Schaltern, Verzögerungen und Integratoren von der Stange, das Anheben von Funktionen in diese Pfeile und das Verbinden der Pfeile, um größere Pfeile zu bilden. Bei der arrowized Functional Reactive Programming bilden die Pfeile eine Schleife, wobei die Eingabe aus der Welt mit der Ausgabe aus der letzten Iteration des Programms kombiniert wird, sodass die Ausgabe auf die Eingabe in der realen Welt reagiert.

Einer der realen Werte ist die Zeit. In Yampa führt der Signalfunktionspfeil den Zeitparameter unsichtbar durch das Computerprogramm - Sie greifen nie auf den Zeitwert zu, aber wenn Sie einen Integratorpfeil in das Programm einbinden, werden über die Zeit integrierte Werte ausgegeben, an die Sie übergeben können andere Pfeile.

14
Robert Onslow

Nur eine Ergänzung zu den anderen Antworten: Persönlich hilft es mir sehr zu verstehen, was ein solches Konzept (mathematisch) ist und wie es sich auf andere Konzepte bezieht, die ich kenne.

Im Fall von Pfeilen fand ich das folgende Papier hilfreich - es vergleicht Monaden, anwendbare Funktoren (Redewendungen) und Pfeile: Redewendungen sind ahnungslos, Pfeile sind akribisch, Monaden sind promiskuitiv von Sam Lindley, Philip Wadler und Jeremy Yallop.

Ich glaube auch, dass niemand diesen Link erwähnt hat, was Ihnen einige Ideen und Literatur zu diesem Thema liefern könnte.

3
Petr Pudlák