Groovy ma pojęcie, które nazywa „curry”. Oto przykład z ich wiki:
def divide = { a, b -> a / b }
def halver = divide.rcurry(2)
assert halver(8) == 4
Rozumiem, co się tutaj dzieje, że prawy argument divide
związany jest z wartością 2. To wydaje się być formą częściowego zastosowania.
Termin curry jest zwykle używany w celu przekształcenia funkcji, która pobiera szereg argumentów w funkcję, która przyjmuje tylko jeden argument i zwraca inną funkcję. Na przykład tutaj jest typ curry
funkcji w Haskell:
curry :: ((a, b) -> c) -> (a -> (b -> c))
Dla ludzi, którzy nie korzystali Haskell a
, b
i c
są wszystkie parametry rodzajowe. curry
przyjmuje funkcję z dwoma argumentami i zwraca funkcję, która pobiera a
i zwraca funkcję od b
do c
. Dodałem dodatkową parę nawiasów do tego typu, aby to wyjaśnić.
Czy źle zrozumiałem, co dzieje się w tym świetnym przykładzie, czy jest to jedynie błędna nazwa częściowego zastosowania? Czy robi to w rzeczywistości obie funkcje: to znaczy przekształca się divide
w funkcję curry, a następnie częściowo stosuje się 2
do tej nowej funkcji.
źródło
Odpowiedzi:
Implementacja
curry
Groovy'ego nie curry w żadnym momencie, nawet za kulisami. Jest zasadniczo identyczny z częściowym zastosowaniem.Te
curry
,rcurry
orazncurry
metody zwracająCurriedClosure
obiekt , który przechowuje związanego argumenty. Ma także metodęgetUncurriedArguments
(źle nazwaną - curry funkcje, a nie argumenty), która zwraca skład argumentów przekazanych mu wraz z powiązanymi argumentami.Kiedy zamknięcie jest wywoływana, to ostatecznie nazywa się
invokeMethod
metodęMetaClassImpl
, która jawnie sprawdza, czy obiekt wywołujący jest instancjąCurriedClosure
. Jeśli tak, wykorzystuje powyższegetUncurriedArguments
do ułożenia pełnej tablicy argumentów do zastosowania:Opierając się na mylącym i nieco niekonsekwentnym nazewnictwie powyżej, podejrzewam, że ktokolwiek to napisał, ma dobre zrozumienie pojęciowe, ale być może był nieco pochopny i - jak wielu inteligentnych ludzi - splątał curry z częściowym zastosowaniem. Jest to zrozumiałe (patrz odpowiedź Paula Kinga), jeśli trochę niefortunne; trudno będzie to naprawić bez naruszenia wstecznej kompatybilności.
Jednym z rozwiązań, które zasugerowałem, jest przeciążenie
curry
metody w taki sposób, że gdy nie zostaną przekazane żadne argumenty, powoduje ona prawdziwe curry i przestaje być wywoływaniem metody z argumentami na korzyść nowejpartial
funkcji. Może to wydawać się trochę dziwne , ale maksymalizuje zgodność wsteczną - ponieważ nie ma powodu, aby używać częściowej aplikacji z zerowymi argumentami - unikając przy tym brzydszej sytuacji (IMHO) posiadania nowej, różnie nazwanej funkcji do właściwego curry, podczas gdy funkcja faktycznie nazwanycurry
robi coś innego i myląco podobnego.Jest
curry
rzeczą oczywistą , że wynik wywołania jest zupełnie inny niż faktyczne curry. Jeśli funkcja naprawdę curry tę funkcję, możesz napisać:… I to by działało, bo
addCurried
powinno działać jak{ x -> { y -> x + y } }
. Zamiast tego generuje wyjątek czasu wykonywania i umierasz trochę w środku.źródło
and you die a little inside
Myślę, że jest jasne, że groovy curry jest w rzeczywistości częściowym zastosowaniem, gdy rozważa się funkcje z więcej niż dwoma argumentami. rozważać
jego curry będzie
jednak curry groovy zwróci coś równoważnego (zakładając, że wywoływany z 1 argumentem x)
która wywoła f o wartości stałej x
tzn. chociaż curry Groovy może zwracać funkcje z argumentami N-1, funkcje curry poprawnie mają tylko 1 argument, dlatego groovy nie może curry z curry
źródło
Groovy zapożyczył nazwy swoich metod curry od wielu innych nieczystych języków FP, które również używają podobnego nazewnictwa do częściowego zastosowania - być może niefortunne dla takiej funkcji skoncentrowanej na FP. Proponuje się kilka „prawdziwych” implementacji curry do włączenia do Groovy. Dobry wątek, aby zacząć o nich czytać, znajduje się tutaj:
http://groovy.markmail.org/thread/c4ycxdzm3ack6xxb
Istniejąca funkcjonalność pozostanie w pewnej formie, a zgodność z poprzednimi wersjami będzie brana pod uwagę podczas wywoływania, jak nazwać nowe metody itp. - dlatego nie mogę powiedzieć na tym etapie, jakie będzie ostateczne nazewnictwo nowych / starych metod być. Prawdopodobnie kompromis w nazewnictwie, ale zobaczymy.
Dla większości programistów OO rozróżnienie między tymi dwoma terminami (curry i częściowe zastosowanie) jest prawdopodobnie w dużej mierze akademickie; jednak gdy już się do nich przyzwyczaisz (i kto będzie utrzymywał twój kod, zostanie przeszkolony w zakresie czytania tego stylu kodowania), wówczas programowanie w stylu bez punktów lub milczenie (które obsługuje „prawdziwe” curry) pozwala na bardziej zwięzłe wyrażanie pewnych algorytmów a w niektórych przypadkach bardziej elegancko. Oczywiste jest tutaj pewne „piękno leży w oczach patrzącego”, ale możliwość obsługi obu stylów jest zgodna z naturą Groovy'ego (OO / FP, static / dynamic, class / scripts itp.).
źródło
Biorąc pod uwagę tę definicję znalezioną w IBM:
halver
to twoja nowa (curry) funkcja (lub zamknięcie), która teraz przyjmuje tylko jeden parametr. Dzwonieniehalver(10)
spowoduje 5.Dlatego przekształca funkcję z n argumentami w funkcję z n-1 argumentami. To samo mówi przykład Haskell, co robi curry.
źródło
rcurry
funkcji (która przyjmuje jeden argument) w funkcję (z teraz tylko jednym argumentem). Połączyłem funkcję curry z argumentem mojej funkcji podstawowej, aby uzyskać wynikową funkcję.n - 1
argumentami. Zobacz przykład na końcu mojej odpowiedzi; zobacz także w dalszej części artykułu, aby uzyskać więcej informacji na temat wprowadzanego rozróżnienia. en.wikipedia.org/wiki/…partial
.