Saya telah melihat referensi untuk fungsi kari di beberapa artikel dan blog tetapi saya tidak dapat menemukan penjelasan yang baik (atau setidaknya satu yang masuk akal!)
653
Saya telah melihat referensi untuk fungsi kari di beberapa artikel dan blog tetapi saya tidak dapat menemukan penjelasan yang baik (atau setidaknya satu yang masuk akal!)
curry
danuncurry
fungsi Haskell. Yang penting di sini adalah isomorfisma ini sudah diperbaiki sebelumnya, dan oleh karena itu "built-in" ke dalam bahasa.add x y = x+y
(kari) berbeda denganadd (x, y)=x+y
(tidak)Jawaban:
Currying adalah ketika Anda memecah fungsi yang mengambil banyak argumen menjadi serangkaian fungsi yang masing-masing hanya mengambil satu argumen. Berikut ini contoh dalam JavaScript:
Ini adalah fungsi yang mengambil dua argumen, a dan b, dan mengembalikan jumlah mereka. Kami sekarang akan menjilat fungsi ini:
Ini adalah fungsi yang mengambil satu argumen, a, dan mengembalikan fungsi yang mengambil argumen lain, b, dan fungsi yang mengembalikan jumlah mereka.
Pernyataan pertama mengembalikan 7, seperti pernyataan add (3, 4). Pernyataan kedua mendefinisikan fungsi baru yang disebut add3 yang akan menambah 3 argumennya. Inilah yang oleh sebagian orang disebut sebagai penutupan. Pernyataan ketiga menggunakan operasi add3 untuk menambah 3 hingga 4, lagi-lagi menghasilkan 7 sebagai hasilnya.
sumber
[1, 2, 3, 4, 5]
yang ingin Anda kalikan dengan angka acak. Di Haskell, saya bisa menulismap (* 5) [1, 2, 3, 4, 5]
untuk mengalikan seluruh daftar dengan5
, dan dengan demikian menghasilkan daftar[5, 10, 15, 20, 25]
.map
harus menjadi fungsi yang hanya membutuhkan 1 argumen - elemen dari daftar. Perkalian - sebagai konsep matematika - adalah operasi biner; dibutuhkan 2 argumen. Namun, dalam Haskell*
adalah fungsi kari, mirip dengan versi keduaadd
dalam jawaban ini. Hasilnya(* 5)
adalah fungsi yang mengambil argumen tunggal dan mengalikannya dengan 5, dan yang memungkinkan kita untuk menggunakannya dengan peta.Dalam aljabar fungsi, berurusan dengan fungsi yang mengambil banyak argumen (atau satu argumen yang setara dengan N-tuple) agak tidak tepat - tetapi, seperti yang dibuktikan oleh Moses Schönfinkel (dan, secara independen, Haskell Curry), itu tidak diperlukan: Anda semua butuhkan adalah fungsi yang mengambil satu argumen.
Jadi, bagaimana Anda menangani sesuatu yang secara alami Anda ungkapkan sebagai, katakanlah
f(x,y)
,? Nah, Anda menganggap itu setara denganf(x)(y)
-f(x)
, sebut sajag
, adalah fungsi, dan Anda menerapkan fungsi ituy
. Dengan kata lain, Anda hanya memiliki fungsi yang mengambil satu argumen - tetapi beberapa fungsi tersebut mengembalikan fungsi lainnya (yang JUGA mengambil satu argumen ;-).Seperti biasa, wikipedia memiliki entri ringkasan yang bagus tentang hal ini, dengan banyak petunjuk bermanfaat (mungkin termasuk yang berhubungan dengan bahasa favorit Anda ;-) dan juga perlakuan matematika yang sedikit lebih ketat.
sumber
div :: Integral a => a -> a -> a
- perhatikan beberapa panah itu? "Map a to function mapping a to a" adalah satu bacaan ;-). Anda bisa menggunakan argumen tuple (tunggal) untukdiv
& c, tapi itu akan benar-benar anti-idiomatis di Haskell.Berikut ini contoh nyata:
Misalkan Anda memiliki fungsi yang menghitung gaya gravitasi yang bekerja pada suatu objek. Jika Anda tidak tahu rumusnya, Anda dapat menemukannya di sini . Fungsi ini mengambil tiga parameter yang diperlukan sebagai argumen.
Sekarang, berada di bumi, Anda hanya ingin menghitung kekuatan untuk objek di planet ini. Dalam bahasa fungsional, Anda bisa meneruskan massa bumi ke fungsi dan kemudian mengevaluasinya sebagian. Apa yang akan Anda dapatkan kembali adalah fungsi lain yang hanya membutuhkan dua argumen dan menghitung gaya gravitasi benda di bumi. Ini disebut kari.
sumber
Currying adalah transformasi yang dapat diterapkan pada fungsi untuk memungkinkan mereka mengambil satu argumen yang kurang dari sebelumnya.
Misalnya, dalam F # Anda dapat mendefinisikan fungsi sebagai berikut: -
Di sini fungsi f mengambil parameter x, y dan z dan menjumlahkannya jadi: -
Pengembalian 6.
Dari definisi kami, kami dapat mendefinisikan fungsi kari untuk f: -
Di mana 'fun x -> fx' adalah fungsi lambda yang setara dengan x => f (x) dalam C #. Fungsi ini menginput fungsi yang ingin Anda gulirkan dan mengembalikan fungsi yang mengambil argumen tunggal dan mengembalikan fungsi yang ditentukan dengan argumen pertama yang diatur ke argumen input.
Dengan menggunakan contoh kami sebelumnya, kami dapat memperoleh kari f dengan demikian: -
Kami kemudian dapat melakukan hal berikut: -
Yang memberi kita fungsi f1 yang setara dengan f1 yz = 1 + y + z. Ini berarti kita dapat melakukan hal berikut: -
Yang mengembalikan 6.
Proses ini sering dikacaukan dengan 'aplikasi fungsi parsial' yang dapat didefinisikan sebagai berikut: -
Meskipun kami dapat memperluasnya ke lebih dari satu parameter, yaitu: -
Aplikasi parsial akan mengambil fungsi dan parameter dan mengembalikan fungsi yang memerlukan satu atau lebih sedikit parameter, dan seperti yang ditunjukkan dua contoh sebelumnya diimplementasikan secara langsung dalam definisi fungsi standar F # sehingga kami dapat mencapai hasil sebelumnya dengan demikian: -
Yang akan mengembalikan hasil 6.
Kesimpulannya:-
Perbedaan antara aplikasi fungsi currying dan sebagian adalah: -
Currying mengambil fungsi dan menyediakan fungsi baru menerima argumen tunggal, dan mengembalikan fungsi yang ditentukan dengan argumen pertama yang diatur ke argumen itu. Ini memungkinkan kami untuk mewakili fungsi dengan beberapa parameter sebagai serangkaian fungsi argumen tunggal . Contoh:-
Aplikasi fungsi parsial lebih langsung - dibutuhkan fungsi dan satu atau lebih argumen dan mengembalikan fungsi dengan argumen n pertama diset ke argumen yang ditentukan. Contoh:-
sumber
Ini bisa menjadi cara untuk menggunakan fungsi untuk membuat fungsi lainnya.
Dalam javascript:
Akan memungkinkan kita untuk menyebutnya seperti ini:
Ketika ini berjalan
10
dilewatkan sebagaix
;yang berarti kami mengembalikan fungsi ini:
Jadi saat Anda menelepon
Anda benar-benar menelepon:
Jadi, jika Anda melakukan ini:
sama dengan:
Jadi kami
addTen()
selalu menambahkan sepuluh untuk apa pun yang kami lewati. Kami dapat membuat fungsi serupa dengan cara yang sama:Sekarang pertanyaan tindak lanjut yang jelas adalah mengapa Anda ingin melakukan itu? Ternyata apa yang ingin operasi
x + y
menjadi satu yang dapat dilewati dengan malas, artinya kita bisa melakukan setidaknya dua hal 1. cache operasi mahal 2. mencapai abstraksi dalam paradigma fungsional.Bayangkan fungsi kari kita terlihat seperti ini:
Kita dapat memanggil fungsi ini satu kali, lalu membagikan hasilnya untuk digunakan di banyak tempat, artinya kita hanya melakukan hal-hal yang mahal secara komputasi sekali:
Kita bisa mendapatkan abstraksi dengan cara yang sama.
sumber
Fungsi curried adalah fungsi dari beberapa argumen yang ditulis ulang sehingga menerima argumen pertama dan mengembalikan fungsi yang menerima argumen kedua dan seterusnya. Ini memungkinkan fungsi beberapa argumen agar sebagian argumen awalnya diterapkan sebagian.
sumber
map
suatu fungsi dif
atas daftar daftarxss
yang dapat Anda lakukanmap (map f) xss
.Berikut contoh mainan dalam Python:
(Hanya menggunakan rangkaian via + untuk menghindari gangguan bagi programmer non-Python.)
Editing untuk menambahkan:
Lihat http://docs.python.org/library/functools.html?highlight=partial#functools.partial , yang juga menunjukkan objek parsial vs perbedaan fungsi dalam cara Python mengimplementasikan ini.
sumber
Currying menerjemahkan fungsi dari callable
f(a, b, c)
menjadi callable asf(a)(b)(c)
.Kalau tidak currying adalah ketika Anda memecah fungsi yang mengambil beberapa argumen menjadi serangkaian fungsi yang mengambil bagian dari argumen.
Secara harfiah, kari adalah transformasi fungsi: dari satu cara memanggil ke cara lain. Dalam JavaScript, kami biasanya membuat pembungkus untuk menjaga fungsi aslinya.
Currying tidak memanggil fungsi. Itu hanya mengubahnya.
Mari kita membuat fungsi kari yang melakukan kari untuk fungsi dua argumen. Dengan kata lain,
curry(f)
untuk dua argumenf(a, b)
diterjemahkan menjadif(a)(b)
Seperti yang Anda lihat, implementasinya adalah serangkaian pembungkus.
curry(func)
adalah pembungkusfunction(a)
.sum(1)
, argumen disimpan di Lingkungan Leksikal, dan pembungkus baru dikembalikanfunction(b)
.sum(1)(2)
akhirnya panggilanfunction(b)
menyediakan 2, dan meneruskan panggilan ke jumlah multi-argumen asli.sumber
Jika Anda mengerti
partial
Anda setengah jalan di sana. Idenyapartial
adalah untuk mengajukan argumen ke suatu fungsi dan mengembalikan fungsi baru yang hanya menginginkan argumen yang tersisa. Ketika fungsi baru ini dipanggil itu termasuk argumen yang dimuat bersama dengan argumen apa pun yang disediakan untuk itu.Dalam Clojure
+
adalah fungsi tetapi untuk membuat semuanya jelas:Anda mungkin sadar bahwa
inc
fungsi itu hanya menambahkan 1 ke nomor apa pun yang dilewati.Mari kita bangun sendiri menggunakan
partial
:Di sini kita mengembalikan fungsi lain yang memiliki 1 dimuat ke argumen pertama
add
. Sepertiadd
mengambil dua argumen,inc
fungsi baru hanya menginginkanb
argumen - bukan 2 argumen seperti sebelumnya karena 1 telah diterapkan sebagian . Dengan demikianpartial
adalah alat untuk membuat fungsi-fungsi baru dengan nilai-nilai standar yang sudah ada sebelumnya. Itu sebabnya dalam fungsi bahasa fungsi sering memerintahkan argumen dari umum ke spesifik. Ini membuatnya lebih mudah untuk menggunakan kembali fungsi tersebut untuk membangun fungsi lainnya.Sekarang bayangkan jika bahasanya cukup pintar untuk memahami secara introspektif yang
add
menginginkan dua argumen. Ketika kami melewati satu argumen, bukannya menolak, bagaimana jika fungsi tersebut menerapkan sebagian argumen yang kami berikan atas nama kami, memahami bahwa kami mungkin bermaksud memberikan argumen yang lain nanti? Kami kemudian dapat mendefinisikaninc
tanpa menggunakan secara eksplisitpartial
.Ini adalah cara beberapa bahasa berperilaku. Ini sangat berguna ketika seseorang ingin menyusun fungsi menjadi transformasi yang lebih besar. Ini akan membawa seseorang ke transduser.
sumber
Saya menemukan artikel ini, dan artikel yang dirujuknya, berguna, untuk lebih memahami currying: http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx
Seperti yang disebutkan lainnya, ini hanyalah cara untuk memiliki fungsi satu parameter.
Ini berguna karena Anda tidak perlu berasumsi berapa banyak parameter yang akan dilewatkan, jadi Anda tidak perlu fungsi 2 parameter, 3 parameter dan 4 parameter.
sumber
Karena semua jawaban lain, currying membantu menciptakan fungsi yang diterapkan sebagian. Javascript tidak menyediakan dukungan asli untuk currying otomatis. Jadi contoh yang diberikan di atas mungkin tidak membantu dalam pengkodean praktis. Ada beberapa contoh yang sangat bagus dalam livcript (Yang pada dasarnya mengkompilasi ke js) http://livescript.net/
Dalam contoh di atas ketika Anda telah memberikan sedikit tidak ada dari argumen, ScriptScript menghasilkan fungsi kari baru untuk Anda (ganda)
sumber
Kari dapat menyederhanakan kode Anda. Ini adalah salah satu alasan utama untuk menggunakan ini. Currying adalah proses mengubah fungsi yang menerima n argumen menjadi n fungsi yang hanya menerima satu argumen.
Prinsipnya adalah untuk meneruskan argumen dari fungsi yang lewat, menggunakan properti closure (penutupan), untuk menyimpannya di fungsi lain dan memperlakukannya sebagai nilai balik, dan fungsi-fungsi ini membentuk rantai, dan argumen terakhir dilewatkan untuk menyelesaikan operasi.
Manfaatnya adalah dapat menyederhanakan pemrosesan parameter dengan menangani satu parameter pada satu waktu, yang juga dapat meningkatkan fleksibilitas dan keterbacaan program. Ini juga membuat program lebih mudah dikelola. Juga membagi kode menjadi potongan-potongan kecil akan membuatnya ramah ulang.
Sebagai contoh:
Saya juga bisa melakukan ...
Ini sangat bagus untuk membuat kode kompleks rapi dan penanganan metode yang tidak disinkronkan dll.
sumber
Fungsi curry diterapkan ke beberapa daftar argumen, bukan hanya satu.
Berikut ini adalah fungsi reguler, non-curried, yang menambahkan dua parameter Int, x dan y:
Ini adalah fungsi yang mirip dengan kari. Alih-alih satu daftar dua parameter Int, Anda menerapkan fungsi ini ke dua daftar masing-masing parameter Int:
Apa yang terjadi di sini adalah bahwa ketika Anda memohon
curriedSum
, Anda benar-benar mendapatkan dua pemanggilan fungsi tradisional kembali ke belakang. Doa fungsi pertama mengambil parameter Int tunggal bernamax
, dan mengembalikan nilai fungsi untuk fungsi kedua. Fungsi kedua ini mengambil parameter Inty
.Berikut adalah nama fungsi
first
yang sesuai dengan apa yangcurriedSum
akan dilakukan doa fungsi tradisional pertama :Menerapkan 1 pada fungsi pertama — dengan kata lain, menjalankan fungsi pertama dan meneruskannya 1 — menghasilkan fungsi kedua:
Menerapkan 2 ke fungsi kedua menghasilkan hasil:
sumber
Contoh currying adalah ketika memiliki fungsi, Anda hanya tahu salah satu parameter saat ini:
Sebagai contoh:
Di sini, karena Anda tidak tahu parameter kedua untuk callback ketika mengirimkannya kepada
performAsyncRequest(_:)
Anda, Anda harus membuat lambda / closure lain untuk mengirim yang itu ke fungsi.sumber
func callback
mengembalikan itu sendiri? Ini disebut @callback(str)
begitulet callback = callback(str)
, panggilan balik hanya nilai pengembalianfunc callback
func callback(_:data:)
menerima dua parameter, di sini saya hanya memberikan satu, ituString
, jadi menunggu yang berikutnya (NSData
), inilah mengapa sekaranglet callback
ada fungsi lain yang menunggu data untuk diteruskanBerikut adalah contoh generik dan versi terpendek untuk fungsi currying dengan n no. dari params.
sumber
Di sini Anda dapat menemukan penjelasan sederhana tentang implementasi kari di C #. Dalam komentar, saya telah mencoba menunjukkan bagaimana kari dapat bermanfaat:
sumber
Currying adalah salah satu fungsi tingkat tinggi dari Java Script.
Currying adalah fungsi dari banyak argumen yang ditulis ulang sehingga mengambil argumen pertama dan mengembalikan fungsi yang pada gilirannya menggunakan argumen yang tersisa dan mengembalikan nilainya.
Bingung?
Mari kita lihat sebuah contoh,
Ini mirip dengan fungsi kari berikut,
Jadi apa artinya kode ini?
Sekarang baca definisi lagi,
Currying adalah fungsi dari banyak argumen yang ditulis ulang sehingga dibutuhkan argumen pertama dan mengembalikan fungsi yang pada gilirannya menggunakan argumen yang tersisa dan mengembalikan nilainya.
Masih bingung? Biarkan saya jelaskan secara mendalam!
Ketika Anda memanggil fungsi ini,
Ini akan mengembalikan Anda fungsi seperti ini,
Jadi, ini disebut fungsi tingkat tinggi. Artinya, Meminta satu fungsi secara bergantian mengembalikan fungsi lainnya adalah definisi yang tepat untuk fungsi tingkat tinggi. Ini adalah keuntungan terbesar untuk legenda, Java Script. Jadi kembalilah ke kari,
Baris ini akan meneruskan argumen kedua ke fungsi curryAdd.
yang pada gilirannya menghasilkan,
Semoga Anda mengerti penggunaan kari di sini. Jadi, Datang ke keuntungan,
Mengapa kari?
Itu menggunakan penggunaan kembali kode. Lebih sedikit kode, Lebih Sedikit Kesalahan. Anda mungkin bertanya bagaimana ini kode kurang?
Saya bisa membuktikannya dengan ECMA script 6 fitur fitur panah baru.
Iya! ECMA 6, berikan kami fitur luar biasa yang disebut fungsi panah,
Dengan bantuan fungsi panah, kita dapat menulis fungsi di atas sebagai berikut,
Keren kan?
Jadi, Kurang Kode dan Sedikit bug !!
Dengan bantuan fungsi tingkat tinggi ini seseorang dapat dengan mudah mengembangkan kode bebas bug.
Aku menantang kamu!
Harapan, Anda mengerti apa yang kari. Silakan berkomentar di sini jika Anda membutuhkan klarifikasi.
Terima kasih, Semoga harimu menyenangkan!
sumber
Ada contoh "Currying in ReasonML".
sumber