Implementasi Groovy currytidak benar-benar menjilat pada titik mana pun, bahkan di belakang layar. Ini pada dasarnya identik dengan aplikasi parsial.
The curry, rcurrydan ncurrymetode mengembalikan CurriedClosureobjek yang memegang argumen terikat. Ini juga memiliki metode getUncurriedArguments(misnamed — you curry functions, not arguments) yang mengembalikan komposisi argumen yang diteruskan kepadanya dengan argumen terikat.
Ketika penutupan dipanggil, akhirnya panggilan itu invokeMethodmetodeMetaClassImpl , yang secara eksplisit memeriksa untuk melihat apakah objek memanggil adalah turunan dari CurriedClosure. Jika demikian, ia menggunakan yang disebutkan di atas getUncurriedArgumentsuntuk menyusun berbagai argumen untuk diterapkan:
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
Berdasarkan nomenklatur yang membingungkan dan agak tidak konsisten di atas, saya curiga bahwa siapa pun yang menulis ini memiliki pemahaman konseptual yang baik, tetapi mungkin sedikit terburu-buru dan — seperti banyak orang pintar — menyulap kari dengan aplikasi sebagian. Ini bisa dimengerti (lihat jawaban Paul King), jika sedikit disayangkan; akan sulit untuk memperbaikinya tanpa merusak kompatibilitas.
Salah satu solusi yang saya sarankan adalah membebani currymetode sedemikian rupa sehingga ketika tidak ada argumen yang dilewatinya itu benar- benar currying, dan mencela memanggil metode dengan argumen yang mendukung partialfungsi baru . Ini mungkin tampak sedikit aneh , tetapi ini akan memaksimalkan kompatibilitas ke belakang — karena tidak ada alasan untuk menggunakan aplikasi parsial dengan argumen nol — sambil menghindari situasi (IMHO) yang lebih buruk dari memiliki fungsi baru yang diberi nama berbeda untuk penjelajahan yang tepat sementara fungsi sebenarnya bernama currymelakukan sesuatu yang berbeda dan membingungkan mirip.
Tak perlu dikatakan bahwa hasil panggilan currysama sekali berbeda dari currying yang sebenarnya. Jika itu benar-benar mengacaukan fungsinya, Anda dapat menulis:
def add = { x, y -> x + y }
def addCurried = add.curry() // should work like { x -> { y -> x + y } }
def add1 = addCurried(1) // should work like { y -> 1 + y }
assert add1(1) == 2
... Dan itu akan berhasil, karena addCurriedharus bekerja seperti { x -> { y -> x + y } }. Sebaliknya itu melempar pengecualian runtime dan Anda mati sedikit di dalam.