Groovy hat ein Konzept, das es "Curry" nennt. Hier ist ein Beispiel aus ihrem Wiki:
def divide = { a, b -> a / b }
def halver = divide.rcurry(2)
assert halver(8) == 4
Ich verstehe, was hier vor sich geht, dass das Argument der rechten Hand divide
an den Wert 2 gebunden ist. Dies scheint eine Form der Teilanwendung zu sein.
Der Begriff currying wird normalerweise verwendet, um eine Funktion, die eine Reihe von Argumenten verwendet, in eine Funktion umzuwandeln, die nur ein Argument verwendet und eine andere Funktion zurückgibt. Zum Beispiel ist hier der Typ der curry
Funktion in Haskell:
curry :: ((a, b) -> c) -> (a -> (b -> c))
Für Leute, die Haskell noch nicht benutzt a
haben b
und c
generische Parameter sind. curry
Nimmt eine Funktion mit zwei Argumenten und gibt eine Funktion zurück, die a
eine Funktion von b
bis annimmt und zurückgibt c
. Ich habe dem Typ ein zusätzliches Paar Klammern hinzugefügt, um dies deutlicher zu machen.
Habe ich falsch verstanden, was im groovigen Beispiel vor sich geht, oder ist es nur eine falsch benannte Teilanwendung? Oder macht es tatsächlich beides: Das heißt, konvertieren divide
in eine Curry-Funktion und dann teilweise 2
auf diese neue Funktion anwenden .
quelle
Antworten:
Groovys Implementierung von
curry
curry nicht einmal hinter den Kulissen. Es ist im Wesentlichen identisch mit der Teilanwendung.Die Methoden
curry
,rcurry
und geben ein Objekt zurück , das die gebundenen Argumente enthält. Es gibt auch eine Methode (falsch benannt - Sie verwenden Curry-Funktionen, keine Argumente), die die Zusammensetzung der Argumente zurückgibt, die mit den gebundenen Argumenten an sie übergeben wurden.ncurry
CurriedClosure
getUncurriedArguments
Wenn ein Closure aufgerufen wird, ruft es letztendlich die
invokeMethod
Methode von aufMetaClassImpl
, die explizit prüft, ob das aufrufende Objekt eine Instanz von istCurriedClosure
. In diesem Fall werden die oben genanntengetUncurriedArguments
Informationen verwendet , um die gesamte Anzahl der anzuwendenden Argumente zusammenzustellen:Aufgrund der verwirrenden und etwas inkonsistenten obigen Nomenklatur vermute ich, dass derjenige, der dies geschrieben hat, ein gutes konzeptuelles Verständnis hat, aber vielleicht ein wenig überstürzt war und - wie viele kluge Leute - das Currying mit einer teilweisen Anwendung in Konflikt brachte. Dies ist verständlich (siehe Antwort von Paul King), wenn auch etwas unglücklich; Es wird schwierig sein, dies zu korrigieren, ohne die Abwärtskompatibilität zu beeinträchtigen.
Eine Lösung, die ich vorgeschlagen habe, besteht darin, die
curry
Methode so zu überladen , dass sie, wenn keine Argumente übergeben werden, tatsächlich ausgeführt wird , und den Aufruf der Methode mit Argumenten zugunsten einer neuenpartial
Funktion nicht mehr zu empfehlen . Dies mag ein wenig seltsam erscheinen , würde jedoch die Abwärtskompatibilität maximieren, da es keinen Grund gibt, eine Teilanwendung mit Nullargumenten zu verwenden, und gleichzeitig die (IMHO) hässlichere Situation vermeiden, eine neue, anders benannte Funktion für das ordnungsgemäße Aufrufen zu haben, während die Funktion tatsächlich ausgeführt wird namedcurry
macht etwas anderes und verwirrend ähnliches.Es versteht sich von selbst, dass sich das Ergebnis eines Anrufs
curry
völlig vom tatsächlichen Currying unterscheidet. Wenn die Funktion wirklich funktioniert, können Sie schreiben:... und es würde funktionieren, denn
addCurried
sollte funktionieren wie{ x -> { y -> x + y } }
. Stattdessen wird eine Laufzeitausnahme ausgelöst und Sie sterben ein wenig im Inneren.quelle
and you die a little inside
Ich denke, es ist klar, dass grooviges Curry tatsächlich eine Teilanwendung ist, wenn Funktionen mit mehr als zwei Argumenten betrachtet werden. Erwägen
seine Curryform wäre
Das Curry von Groovy gibt jedoch etwas zurück, das dem entspricht (vorausgesetzt, es wird mit 1 Argument x aufgerufen).
welches f mit dem Wert von a fest auf x aufruft
Das heißt, während Groovys Curry Funktionen mit N-1 Argumenten zurückgeben kann, haben Curry-Funktionen eigentlich immer nur 1 Argument, daher kann Groovy nicht mit Curry curren
quelle
Groovy übernahm die Benennung seiner Curry-Methoden aus zahlreichen anderen nicht reinen FP-Sprachen, die ebenfalls ähnliche Benennungen für Teilanwendungen verwenden - was für eine solche FP-zentrierte Funktionalität möglicherweise unglücklich ist. Es werden mehrere "echte" Currying-Implementierungen zur Aufnahme in Groovy vorgeschlagen. Ein guter Thread, um darüber zu lesen, ist hier:
http://groovy.markmail.org/thread/c4ycxdzm3ack6xxb
Die vorhandene Funktionalität bleibt in irgendeiner Form erhalten und die Abwärtskompatibilität wird berücksichtigt, wenn aufgerufen wird, wie die neuen Methoden benannt werden sollen usw. - daher kann ich zum gegenwärtigen Zeitpunkt nicht sagen, wie die endgültigen Namen der neuen / alten Methoden lauten sollen Sein. Wahrscheinlich ein Kompromiss bei der Benennung, aber wir werden sehen.
Für die meisten OO-Programmierer ist die Unterscheidung zwischen den beiden Begriffen (Currying und Teilanwendung) wohl weitgehend akademisch; Sobald Sie sich jedoch an diese gewöhnt haben (und wer auch immer Ihren Code warten wird, ist darin geschult, diese Art der Codierung zu lesen), können Sie bestimmte Arten von Algorithmen durch punktfreie oder stillschweigende Programmierung (die von "echten" Lehrmethoden unterstützt wird) kompakter ausdrücken und in einigen Fällen eleganter. Hier liegt offensichtlich etwas "Schönheit in den Augen des Betrachters", aber die Fähigkeit, beide Stile zu unterstützen, liegt in der Natur von Groovy (OO / FP, statisch / dynamisch, Klassen / Skripte usw.).
quelle
In Anbetracht dieser bei IBM gefundenen Definition:
halver
ist Ihre neue (Curry-) Funktion (oder Schließung), die jetzt nur einen Parameter übernimmt. Ein Anrufhalver(10)
würde zu 5 führen.Dafür transformiert es eine Funktion mit n Argumenten in eine Funktion mit n-1 Argumenten. Dasselbe gilt für Ihr Haskell-Beispiel für Curry.
quelle
rcurry
Funktion (die ein Argument annimmt) in eine Funktion (mit nur einem Argument). Ich habe die Curry-Funktion mit einem Argument an meine Basisfunktion angekettet, um meine resultierende Funktion zu erhalten.n - 1
Argumenten. Siehe das Beispiel am Ende meiner Antwort; Weitere Informationen zur Unterscheidung finden Sie später in diesem Artikel. en.wikipedia.org/wiki/…partial
.