Implementasi Groovy curry
tidak benar-benar menjilat pada titik mana pun, bahkan di belakang layar. Ini pada dasarnya identik dengan aplikasi parsial.
The curry
, rcurry
dan ncurry
metode mengembalikan CurriedClosure
objek 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 invokeMethod
metodeMetaClassImpl
, yang secara eksplisit memeriksa untuk melihat apakah objek memanggil adalah turunan dari CurriedClosure
. Jika demikian, ia menggunakan yang disebutkan di atas getUncurriedArguments
untuk 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 curry
metode sedemikian rupa sehingga ketika tidak ada argumen yang dilewatinya itu benar- benar currying, dan mencela memanggil metode dengan argumen yang mendukung partial
fungsi 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 curry
melakukan sesuatu yang berbeda dan membingungkan mirip.
Tak perlu dikatakan bahwa hasil panggilan curry
sama 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 addCurried
harus bekerja seperti { x -> { y -> x + y } }
. Sebaliknya itu melempar pengecualian runtime dan Anda mati sedikit di dalam.