Groovy memiliki konsep yang disebut 'currying'. Berikut ini contoh dari wiki mereka:
def divide = { a, b -> a / b }
def halver = divide.rcurry(2)
assert halver(8) == 4
Pemahaman saya tentang apa yang terjadi di sini adalah bahwa argumen tangan kanan divide
sedang terikat dengan nilai 2. Ini seperti bentuk aplikasi parsial.
Istilah currying biasanya digunakan untuk mengubah fungsi yang mengambil serangkaian argumen menjadi fungsi yang hanya membutuhkan satu argumen dan mengembalikan fungsi lainnya. Sebagai contoh di sini adalah jenis curry
fungsi di Haskell:
curry :: ((a, b) -> c) -> (a -> (b -> c))
Untuk orang yang belum pernah menggunakan Haskell a
, b
dan c
semuanya adalah parameter umum. curry
mengambil fungsi dengan dua argumen, dan mengembalikan fungsi yang mengambil a
dan mengembalikan fungsi dari b
ke c
. Saya telah menambahkan sepasang kurung tambahan ke jenisnya untuk membuatnya lebih jelas.
Pernahkah saya salah paham tentang apa yang terjadi dalam contoh asyik atau hanya sebagian aplikasi yang salah? Atau apakah itu memang melakukan keduanya: yaitu mengkonversi divide
menjadi fungsi kari dan kemudian sebagian berlaku 2
untuk fungsi baru ini.
sumber
Jawaban:
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
danncurry
metode mengembalikanCurriedClosure
objek yang memegang argumen terikat. Ini juga memiliki metodegetUncurriedArguments
(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 dariCurriedClosure
. Jika demikian, ia menggunakan yang disebutkan di atasgetUncurriedArguments
untuk menyusun berbagai argumen untuk diterapkan: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 mendukungpartial
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 bernamacurry
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:... Dan itu akan berhasil, karena
addCurried
harus bekerja seperti{ x -> { y -> x + y } }
. Sebaliknya itu melempar pengecualian runtime dan Anda mati sedikit di dalam.sumber
and you die a little inside
Saya pikir jelas bahwa asyik kari sebenarnya aplikasi parsial ketika mempertimbangkan fungsi dengan lebih dari dua argumen. mempertimbangkan
bentuk karinya adalah
Namun kari groovy akan mengembalikan sesuatu yang setara (dengan asumsi dipanggil dengan 1 argumen x)
yang akan memanggil f dengan nilai tetap ke x
yaitu sementara kari groovy dapat mengembalikan fungsi dengan argumen N-1, fungsi kari dengan benar hanya pernah memiliki 1 argumen, oleh karena itu groovy tidak dapat kari dengan kari
sumber
Groovy meminjam penamaan metode kari dari banyak bahasa FP non-murni lainnya yang juga menggunakan penamaan yang serupa untuk aplikasi parsial - mungkin disayangkan untuk fungsi FP-centric tersebut. Ada beberapa implementasi kari "nyata" yang diusulkan untuk dimasukkan dalam Groovy. Sebuah utas yang baik untuk mulai membaca tentang mereka ada di sini:
http://groovy.markmail.org/thread/c4ycxdzm3ack6xxb
Fungsionalitas yang ada akan tetap dalam beberapa bentuk dan kompatibilitas ke belakang akan dipertimbangkan ketika melakukan panggilan pada apa yang akan memberi nama metode baru dll. - jadi saya tidak bisa mengatakan pada tahap ini apa penamaan akhir dari metode baru / lama akan menjadi. Mungkin kompromi pada penamaan tetapi kita akan lihat.
Bagi kebanyakan programmer OO perbedaan antara dua istilah (currying dan aplikasi parsial) bisa dibilang sebagian besar bersifat akademis; Namun, begitu Anda terbiasa dengan mereka (dan siapa pun yang akan menjaga kode Anda dilatih untuk membaca gaya pengkodean ini) maka pemrograman gaya point-free atau diam-diam (yang mendukung kari "nyata" mendukung) memungkinkan jenis algoritma tertentu untuk diekspresikan lebih kompak. dan dalam beberapa kasus lebih elegan. Jelas ada beberapa "keindahan terletak di mata yang melihatnya" di sini tetapi memiliki kemampuan untuk mendukung kedua gaya sesuai dengan sifat Groovy (OO / FP, statis / dinamis, kelas / skrip dll).
sumber
Mengingat definisi ini ditemukan di IBM:
halver
adalah fungsi (atau kari) baru Anda, yang sekarang hanya membutuhkan satu parameter. Panggilanhalver(10)
akan menghasilkan 5.Untuk itu mengubah fungsi dengan argumen n dalam fungsi dengan argumen n-1. Hal yang sama dikatakan oleh haskell Anda contoh apa yang kari lakukan.
sumber
rcurry
fungsi (yang mengambil satu argumen) menjadi fungsi (dengan sekarang hanya satu argumen). Saya merantai fungsi kari dengan argumen ke fungsi basis saya untuk mendapatkan fungsi yang dihasilkan.n - 1
argumen. Lihat contoh di akhir jawaban saya; lihat juga nanti di artikel untuk lebih lanjut tentang perbedaan yang dibuat. en.wikipedia.org/wiki/…partial
.