Reihenfolge der Parameter, um das Currying zu nutzen

93

Ich habe kürzlich zweimal Code überarbeitet, um die Reihenfolge der Parameter zu ändern, da zu viel Code vorhanden war, in dem Hacks gefallen flipoder \x -> foo bar x 42stattgefunden haben.

Welche Prinzipien helfen mir beim Entwerfen einer Funktionssignatur, das Currying optimal zu nutzen?

John F. Miller
quelle

Antworten:

111

Für Sprachen, die Currying und Teilanwendung problemlos unterstützen, gibt es eine überzeugende Reihe von Argumenten, die ursprünglich von Chris Okasaki stammen:

  • Geben Sie die Datenstruktur als letztes Argument an

Warum? Sie können dann Operationen an den Daten gut zusammenstellen. ZB insert 1 $ insert 2 $ insert 3 $ s. Dies hilft auch bei Funktionen im Status .

Standardbibliotheken wie "Container" folgen dieser Konvention .

Manchmal werden alternative Argumente angegeben, um die Datenstruktur an die erste Stelle zu setzen, damit sie geschlossen werden kann, wodurch Funktionen für eine statische Struktur (z. B. Nachschlagen) erhalten werden, die etwas präziser sind. Der breite Konsens scheint jedoch zu sein, dass dies weniger ein Gewinn ist, zumal es Sie zu stark in Klammern gesetztem Code treibt.

  • Setzen Sie das unterschiedlichste Argument zuletzt

Bei rekursiven Funktionen wird häufig das Argument verwendet, das am stärksten variiert (z. B. ein Akkumulator), als letztes Argument, während das Argument, das am wenigsten variiert (z. B. ein Funktionsargument), am Anfang steht. Dies passt gut zum letzten Stil der Datenstruktur.


Eine Zusammenfassung der Okasaki-Ansicht finden Sie in seiner Edison-Bibliothek (wieder eine andere Datenstrukturbibliothek):

  • Teilanwendung : Argumente, die eher statisch sind, werden normalerweise vor anderen Argumenten angezeigt, um die Teilanwendung zu erleichtern.
  • Sammlung wird zuletzt angezeigt : In allen Fällen, in denen eine Operation eine einzelne Sammlung abfragt oder eine vorhandene Sammlung ändert, wird das Sammlungsargument zuletzt angezeigt . Dies ist so etwas wie ein De-facto-Standard für Haskell-Datenstrukturbibliotheken und verleiht der API ein gewisses Maß an Konsistenz.
  • Üblichste Reihenfolge : Wenn eine Operation eine bekannte mathematische Funktion für mehr als eine Datenstruktur darstellt, werden die Argumente so ausgewählt, dass sie mit der üblichsten Argumentreihenfolge für die Funktion übereinstimmen.
Don Stewart
quelle
Geben Sie als Folge des ersten Aufzählungspunkts auch das Argument an, das möglicherweise zuletzt in einer Datenstruktur vorhanden ist. Es macht Karte, Falte und Freunde sauberer. tl; dr Sache in der Liste gehen zuletzt.
John F. Miller
1
Lookup kann sowieso nicht verkettet werden, daher unterstützt der erste Punkt dies nicht. haskell.org/haskellwiki/Parameter_order macht ein zwingendes Argument umgekehrt: "Da Objekte vom Typ Map Zuordnungen darstellen, ist es natürlich, eine Funktion zu haben, die ein Map-Objekt in die dargestellte Funktion umwandelt."
Brandon
11

Platzieren Sie die Argumente, die Sie am wahrscheinlichsten wiederverwenden, zuerst. Funktionsargumente sind dafür ein gutes Beispiel. Es ist viel wahrscheinlicher, dass map fSie zwei verschiedene Listen verwenden möchten , als dass Sie viele verschiedene Funktionen derselben Liste zuordnen möchten.

Hammar
quelle
5
Wenn Sie tatsächlich viele Funktionen derselben Liste zuordnen, sollten Sie möglicherweise eine Liste von Funktionen und map ($myList)stattdessen diese Liste erstellen.
Tintenfisch
3

Ich neige dazu, das zu tun, was Sie getan haben, eine Bestellung auszuwählen, die gut erscheint, und dann umzugestalten, wenn sich herausstellt, dass eine andere Bestellung besser ist. Die Reihenfolge hängt stark davon ab, wie Sie die Funktion (natürlich) verwenden werden.

August
quelle