Penjelasan kombinator untuk pekerja itu

93

Apa itu kombinator ??

Apakah ini "fungsi atau definisi tanpa variabel bebas" (sebagaimana didefinisikan pada SO)?

Atau bagaimana dengan ini: menurut John Hughes dalam makalahnya yang terkenal tentang Arrows, "kombinator adalah fungsi yang membangun fragmen program dari fragmen program" , yang menguntungkan karena "... pemrogram yang menggunakan kombinator membangun sebagian besar dari yang diinginkan memprogram secara otomatis, daripada menulis setiap detail dengan tangan ". Dia melanjutkan dengan mengatakan itu mapdan filteradalah dua contoh umum dari kombinator semacam itu.

Beberapa kombinator yang cocok dengan definisi pertama:

Beberapa kombinator yang cocok dengan definisi kedua:

  • peta
  • Saring
  • lipat / kurangi (mungkin)
  • salah satu dari >> =, buat, fmap ?????

Saya tidak tertarik dengan definisi pertama - itu tidak akan membantu saya untuk menulis program nyata (+1 jika Anda meyakinkan saya bahwa saya salah). Tolong bantu saya memahami definisi kedua . Saya pikir peta, filter, dan pengurangan berguna: mereka memungkinkan saya untuk memprogram pada tingkat yang lebih tinggi - lebih sedikit kesalahan, kode yang lebih pendek dan lebih jelas. Berikut adalah beberapa pertanyaan spesifik saya tentang kombinator:

  1. Apa lagi contoh kombinator seperti peta, filter?
  2. Kombinator apa yang sering diterapkan oleh bahasa pemrograman?
  3. Bagaimana kombinator dapat membantu saya merancang API yang lebih baik?
  4. Bagaimana cara merancang kombinator yang efektif?
  5. Apa yang mirip dengan kombinator dalam bahasa non-fungsional (katakanlah, Java), atau apa yang digunakan bahasa berikut sebagai pengganti kombinator?

Memperbarui

Berkat @CA McCann, saya sekarang memiliki pemahaman yang lebih baik tentang kombinator. Tapi satu pertanyaan masih menjadi poin penting bagi saya:

Apa perbedaan antara program fungsional yang ditulis dengan, dan yang ditulis tanpa, penggunaan kombinator yang berat?

Saya menduga jawabannya adalah bahwa versi kombinator-berat lebih pendek, lebih jelas, lebih umum, tetapi saya akan menghargai diskusi yang lebih mendalam, jika memungkinkan.

Saya juga mencari lebih banyak contoh dan penjelasan tentang kombinator kompleks (yaitu lebih kompleks daripada fold) dalam bahasa pemrograman umum.

Matt Fenwick
sumber
4
Saya mempertimbangkan map / filter / fold Higher-order Functions dan saya menggunakannya sepanjang waktu. Saya masih tidak tahu apa itu kombinator.
1
@pst - Saya akan setuju 5 hari yang lalu, tetapi sekarang saya tidak dapat berdebat dengan John Hughes
Matt Fenwick

Jawaban:

93

Saya tidak tertarik dengan definisi pertama - itu tidak akan membantu saya untuk menulis program nyata (+1 jika Anda meyakinkan saya bahwa saya salah). Tolong bantu saya memahami definisi kedua. Saya pikir peta, filter, dan pengurangan berguna: mereka memungkinkan saya untuk memprogram pada tingkat yang lebih tinggi - lebih sedikit kesalahan, kode yang lebih pendek dan lebih jelas.

Kedua definisi tersebut pada dasarnya adalah hal yang sama. Yang pertama didasarkan pada definisi formal dan contoh yang Anda berikan adalah kombinator primitif - blok penyusun sekecil mungkin. Mereka dapat membantu Anda menulis program nyata sejauh, dengan mereka, Anda dapat membangun kombinator yang lebih canggih. Pikirkan kombinator seperti S dan K sebagai bahasa mesin dari "komputer kombinatori" hipotetis. Komputer sebenarnya tidak bekerja seperti itu, tentu saja, jadi dalam praktiknya Anda biasanya akan memiliki operasi tingkat yang lebih tinggi yang diimplementasikan di belakang layar dengan cara lain, tetapi fondasi konseptual masih merupakan alat yang berguna untuk memahami arti dari level yang lebih tinggi tersebut. operasi.

Definisi kedua yang Anda berikan lebih informal dan tentang penggunaan kombinator yang lebih canggih, dalam bentuk fungsi tingkat tinggi yang menggabungkan fungsi lain dengan berbagai cara. Perhatikan bahwa jika blok penyusun dasar adalah kombinator primitif di atas, semua yang dibangun darinya adalah fungsi tingkat tinggi dan juga kombinator. Namun, dalam bahasa di mana primitif lain ada, Anda memiliki perbedaan antara hal-hal yang berfungsi atau bukan, dalam hal ini kombinator biasanya didefinisikan sebagai fungsi yang memanipulasi fungsi lain secara umum, daripada beroperasi pada non- berfungsi secara langsung.

Apa lagi contoh kombinator seperti peta, filter?

Terlalu banyak untuk dicantumkan! Keduanya mengubah fungsi yang mendeskripsikan perilaku pada satu nilai menjadi fungsi yang mendeskripsikan perilaku di seluruh koleksi. Anda juga bisa memiliki fungsi yang hanya mengubah fungsi lain, seperti menyusunnya ujung ke ujung, atau memisahkan dan menggabungkan kembali argumen. Anda dapat memiliki kombinator yang mengubah operasi satu langkah menjadi operasi rekursif yang menghasilkan atau menggunakan koleksi. Atau segala macam hal lainnya, sungguh.

Kombinator apa yang sering diterapkan oleh bahasa pemrograman?

Itu akan sedikit berbeda. Ada relatif sedikit kombinator yang benar-benar generik - kebanyakan yang primitif yang disebutkan di atas - jadi dalam banyak kasus kombinator akan memiliki kesadaran akan setiap struktur data yang digunakan (bahkan jika struktur data tersebut dibangun dari kombinator lain), di mana Jika biasanya ada segelintir kombinator "generik penuh" dan kemudian berbagai bentuk khusus apa pun yang diputuskan untuk diberikan oleh seseorang. Ada sejumlah kasus konyol di mana (versi umum yang sesuai dari) peta, lipatan, dan pembukaan sudah cukup untuk melakukan hampir semua yang Anda inginkan.

Bagaimana kombinator dapat membantu saya merancang API yang lebih baik?

Persis seperti yang Anda katakan, dengan berpikir dalam kerangka operasi tingkat tinggi, dan cara mereka berinteraksi, alih-alih detail tingkat rendah.

Pikirkan tentang popularitas loop gaya "untuk setiap" di atas koleksi, yang memungkinkan Anda mengabstraksi detail penghitungan koleksi. Ini hanya operasi map / lipat dalam banyak kasus, dan dengan menjadikannya kombinator (bukan sintaks bawaan) Anda dapat melakukan hal-hal seperti mengambil dua loop yang ada dan langsung menggabungkannya dalam berbagai cara - menumpuk satu di dalam yang lain, lakukan satu demi satu, dan seterusnya - dengan hanya menerapkan kombinator, daripada menyulap sejumlah besar kode.

Bagaimana cara merancang kombinator yang efektif?

Pertama, pikirkan tentang operasi apa yang masuk akal pada data apa pun yang digunakan program Anda. Kemudian pikirkan tentang bagaimana operasi tersebut dapat digabungkan secara bermakna dengan cara umum, serta bagaimana operasi dapat dipecah menjadi bagian-bagian kecil yang dihubungkan kembali. Hal utama adalah bekerja dengan transformasi dan operasi , bukan tindakan langsung . Ketika Anda memiliki fungsi yang hanya melakukan sedikit fungsionalitas yang rumit dengan cara yang tidak jelas dan hanya mengeluarkan semacam hasil pra-cerna, tidak banyak yang dapat Anda lakukan dengan itu. Biarkan hasil akhir pada kode yang menggunakan kombinator - Anda menginginkan hal-hal yang membawa Anda dari titik A ke titik B, bukan hal-hal yang diharapkan menjadi awal atau akhir dari suatu proses.

Apa yang mirip dengan kombinator dalam bahasa non-fungsional (katakanlah, Java), atau apa yang digunakan bahasa berikut sebagai pengganti kombinator?

Ahahahaha. Lucu Anda harus bertanya, karena objek benar-benar merupakan benda tingkat tinggi di tempat pertama - mereka memiliki beberapa data, tetapi mereka juga membawa banyak operasi, dan cukup banyak dari apa yang merupakan desain OOP yang baik bermuara pada "objek harus biasanya bertindak seperti kombinator, bukan struktur data ".

Jadi mungkin jawaban terbaik di sini adalah bahwa alih-alih hal-hal seperti kombinator, mereka menggunakan kelas dengan banyak metode pengambil dan penyetel atau bidang publik, dan logika yang sebagian besar terdiri dari melakukan tindakan buram dan ditentukan sebelumnya.

CA McCann
sumber
Jawaban yang bagus! Mari kita lihat apakah saya memahaminya - kombinator tidak istimewa, melainkan merupakan bagian integral dari membangun sistem perangkat lunak yang dapat dipelihara? Saya masih mencoba mencerna pernyataan "fragmen program" Hughes, dalam konteks posting Anda.
Matt Fenwick
@ Matt Fenwick: Saya cukup yakin dia hanya menggunakan "fragmen program" untuk mengartikan jenis transformasi / operasi yang saya bicarakan, terutama jika itu berbicara tentang "Panah", yang menekankan pendekatan itu lebih kuat lagi. Juga, saya tidak akan mengatakan ini tentang membangun sistem yang dapat dipelihara dengan tepat - lebih banyak tentang membangun sistem yang sangat modular dan dipisahkan dengan cara tertentu , dengan manfaat yang menyertainya.
CA McCann
Apakah Anda mengetahui sumber daya yang bagus untuk membaca tentang penggunaan praktis kombinator? Terima kasih banyak!
Matt Fenwick
@Matt Fenwick: Tidak ada yang spesifik dari pikiran saya, maaf. Namun, ini cenderung menjadi pendekatan alami untuk program yang ditulis dengan gaya yang sangat fungsional, jadi hanya menghabiskan waktu dengan bahasa yang sangat mendorongnya (misalnya, Haskell atau Clojure), dan melihat bagaimana kode yang bersih dan idiomatik ditulis dalam bahasa itu. , adalah cara yang cukup bagus untuk merasakan gayanya.
CA McCann