Haskell-Funktionszusammensetzung (.) Und Funktionsanwendungs-Idiome ($): korrekte Verwendung

129

Ich habe Real World Haskell gelesen und nähere mich dem Ende, aber eine Frage des Stils hat mich wegen der (.)und ($)-Operatoren belästigt .

Wenn Sie eine Funktion schreiben, die aus anderen Funktionen besteht, schreiben Sie sie wie folgt:

f = g . h

Aber wenn Sie etwas auf das Ende dieser Funktionen anwenden, schreibe ich es so:

k = a $ b $ c $ value

Aber das Buch würde es so schreiben:

k = a . b . c $ value

Für mich sehen sie jetzt funktional gleichwertig aus, sie tun genau das Gleiche in meinen Augen. Je mehr ich jedoch hinschaue, desto mehr sehe ich Menschen, die ihre Funktionen so schreiben, wie es das Buch tut: zuerst komponieren (.)und dann erst am Ende ($)einen Wert anhängen, um das Los zu bewerten (niemand macht es mit vielen Dollarkompositionen). .

Gibt es einen Grund für die Verwendung der Bücher, der viel besser ist als die Verwendung aller ($)Symbole? Oder gibt es hier eine bewährte Methode, die ich nicht bekomme? Oder ist es überflüssig und ich sollte mir überhaupt keine Sorgen machen?

Robert Massaioli
quelle
4
Beachten Sie, dass das zweite Beispiel alsk = a $ b $ c value
Thomas Eding
1
Ja, das kann es, wie Zifre unten erwähnte, aber ich habe beschlossen, es dort zu lassen, da es nichts schadet und seine (und jetzt Ihre) Kommentare Sinn machen. Trotzdem danke. +1 :)
Robert Massaioli
2
Ein anderer gängiger Ansatz ist a . b $ c value, dass ich nicht so sehr mag wie das dritte Beispiel, aber ein paar Zeichen speichere.
John L

Antworten:

153

Ich denke, ich kann dies von der Autorität aus beantworten.

Gibt es einen Grund für die Verwendung der Bücher, der viel besser ist als die Verwendung aller ($) Symbole?

Es gibt keinen besonderen Grund. Bryan und ich ziehen es vor, das Leitungsrauschen zu reduzieren. .ist leiser als $. Infolgedessen verwendet das Buch die f . g . h $ xSyntax.

Don Stewart
quelle
3
Nun, ich kann nicht auf eine bessere Antwort hoffen als diese; von einem der Autoren selbst. :) Und das macht Sinn, es sieht auf der Seite beim Lesen viel leiser aus. Markieren Sie dies als Antwort, da es die Frage direkt beantwortet. Danke für die Antwort; und tatsächlich das Buch.
Robert Massaioli
38
Nicht mit dem Autor nicht einverstanden zu sein, aber ich denke, es gibt einen anderen wichtigeren Grund im mentalen Modell , etwas zu erschaffen , anstatt es zu benutzen . Haskell-Benutzer möchten sich f.g.heher eine neue clevere Kreation vorstellen f(g(h())). Jetzt rufen sie eine neue, wenn auch anonyme Funktion auf, die sie erstellt haben, anstatt nur ein großes Wörterbuch vorgefertigter Funktionsaufrufe wie ein PHP-Benutzer zu verketten.
Evan Carroll
1
Das ist eine interessante Aussage: "Leitungsrauschen reduzieren" und "leiser als". Ich habe nie über Programmiersprachen in dieser Terminologie nachgedacht, aber es macht vollkommen Sinn.
Rabarberski
53

Sie sind in der Tat gleichwertig: Denken Sie daran, dass der $Bediener im Wesentlichen nichts tut. f $ xbewertet zu f x. Der Zweck von $ist sein Fixitätsverhalten: rechtsassoziative und minimale Priorität. Wenn Sie $Klammern für die Gruppierung anstelle der Infix-Priorität entfernen und verwenden, sehen die Code-Snippets folgendermaßen aus:

k = a (b (c (value)))

und

k = (a . b . c) value

Der Grund für den Vorzug der .Version gegenüber der $Version ist der gleiche Grund für den Vorzug beider gegenüber der oben in Klammern gesetzten Version: Ästhetik.

Einige mögen sich jedoch fragen, ob die Verwendung von Infix-Operatoren anstelle von Klammern auf einem unbewussten Drang beruht, eine mögliche Ähnlichkeit mit Lisp zu vermeiden (nur ein Scherz ... denke ich?).

CA McCann
quelle
38

Ich würde , dass in hinzufügen f . g $ x, f . gist eine sinnvolle syntaktische Einheit.

Inzwischen in f $ g $ x, f $ gist keine sinnvolle Einheit. Eine Kette von $ist wohl mehr zwingend notwendig - zunächst das Ergebnis erhalten von gder x, dann tut fes, dann tut fooes, dann usw.

In der Zwischenzeit ist eine Kette von .wohl deklarativer und in gewisser Weise näher an einer datenflusszentrierten Ansicht - komponieren Sie eine Reihe von Funktionen und wenden Sie sie letztendlich auf etwas an.

sclv
quelle
2
Ich lerne Haskell (habe nichts Sinnvolles codiert), aber ich stelle mir $ gerne als eine Art "Pipe" -Operator vor. Es ist dem Terminal sehr ähnlich Pipe (mit Ausnahme der Datenflüsse von rechts nach links), aber wie bei Terminalprozessen ist jede Einheit explizit unabhängig.
LostSalad
1
Der $Operator scheint sich ähnlich zu verhalten wie der <|Operator in F #. Ich glaube, beide sind tatsächlich gleich definiert - in F # (<|) a b = a bund in Haskell a $ b = a b, die im Wesentlichen gleichwertig sind.
Tom Galvin
@Quackmatic Ziemlich sicher, dass es (<|) b a = a bin F # ist, da es wie verwendet wird [1; 2; 3; 4; 5] <| List.map ((+) 1), wenn Speicher dient.
BalinKingOfMoria CMs wieder herstellen
@BalinKingOfMoria Der <|Operator übergibt den Wert an die Funktion, anstatt die Funktion an den Wert zu übergeben. Ihr Codebeispiel würde |>stattdessen mit dem Operator funktionieren .
Tom Galvin
@ Quackmatic Oh. Wusste nicht, dass es mehrere Versionen gab (ich habe F # nicht sehr oft verwendet).
BalinKingOfMoria CMs wieder herstellen
18

Für mich ist die Antwort (a) die Ordentlichkeit, wie Don sagte ; und (b) ich stelle fest, dass meine Funktion beim Bearbeiten von Code möglicherweise punktfrei ist, und dann muss ich nur noch den letzten löschen, $anstatt zurück zu gehen und alles zu ändern. Ein kleiner Punkt, aber eine nette.

Antal Spector-Zabusky
quelle
Ja, das ist ein guter Grund, es so zu schreiben. Wenn Sie mit einer Funktionskomposition enden möchten, ist es schneller. :) Yay für das Speichern von Tastenanschlägen, aber was noch wichtiger ist, Zeit. +1
Robert Massaioli
13

Es gibt eine interessante Diskussion dieser Frage in diesem Hashkell-Cafe-Thread . Offenbar gibt es eine Minderheit Sicht , die besagt , dass das Recht Assoziativität von $ist „einfach falsch“ , und wählen Sie f . g . h $ xüber f $ g $ h $ xist ein Weg , um das Problem Seiten treten.

Travis Brown
quelle
Hey, du hast eine ganze Diskussion zu diesem Thema gefunden. Das ist großartig, ich lese gerade. +1
Robert Massaioli
2
Ähnliche Argumente hier: ghc.haskell.org/trac/haskell-prime/wiki/…
enrique
Beachten Sie, dass dies $!auch die "einfach falsche" richtige Assoziativität hat - Warum ist das $! Betreiber rechtsassoziativ? .
imz - Ivan Zakharyaschev
3

Es ist nur eine Frage des Stils. Die Art und Weise, wie das Buch es macht, macht für mich jedoch mehr Sinn. Es setzt alle Funktionen zusammen und wendet sie dann auf den Wert an.

Ihre Methode sieht einfach seltsam aus und die letzte $ist unnötig.

Es ist jedoch wirklich egal. In Haskell gibt es normalerweise viele, viele, richtige Wege, um dasselbe zu tun.

Zifre
quelle
3
Ich habe nicht bemerkt, dass der letzte Dollar unnötig war, aber ich hätte es tun sollen. Danke und ich werde es dort lassen, damit die Leute wissen, was dieser Kommentar bedeutet.
Robert Massaioli
0

Mir ist klar, dass dies eine sehr alte Frage ist, aber ich denke, es gibt einen anderen Grund dafür, der nicht erwähnt wurde.

Wenn Sie eine neue punktfreie Funktion deklarieren f . g . h, wird der übergebene Wert automatisch angewendet. Wenn Sie jedoch schreiben f $ g $ h, wird es nicht funktionieren.

Ich denke, der Grund, warum der Autor die Kompositionsmethode bevorzugt, ist, dass sie zu einer guten Praxis beim Aufbau von Funktionen führt.

Hackeryarn
quelle