Apakah rekursi menjadi contoh "terlalu pintar" saat pemrograman?

8

Saya telah membaca beberapa buku dan belajar melalui pengalaman bahwa mengoptimalkan kode ke titik di mana itu tidak dapat dipahami, atau menghasilkan solusi yang sangat cepat tetapi sangat kompleks untuk suatu masalah tidak diinginkan ketika bekerja dalam tim, atau bahkan ketika Anda sedang bekerja sendiri dan harus memahami solusi cerdas Anda beberapa waktu kemudian.

Pertanyaan saya adalah, apakah rekursi harus diperlakukan dengan cara yang sama? Apakah programmer rata-rata memahami rekursi dengan mudah dan karenanya seseorang harus menggunakannya dengan impunitas, atau apakah programmer rata-rata tidak memahami rekursi dengan baik dan seseorang harus menjauh darinya demi produktivitas tim secara keseluruhan?

Saya tahu ada jawaban sederhana dari, "Setiap programmer yang tidak memahami rekursi tidak sepadan, jadi jangan khawatir tentang mereka" tetapi saya bertanya-tanya apakah Anda semua memiliki pengalaman dunia nyata yang ingin Anda ikuti bagian yang akan menerangi masalah lebih dari pendapat yang baru saja saya sebutkan.

Biara Macy
sumber
2
Pertanyaan ini sangat mirip dengan programer.stackexchange.com/questions/24997/... yang juga ditanyakan hari ini. Beberapa jawaban bagus di sana.
Nicole
4
Bagaimana Anda bisa menjadi programmer biasa jika Anda tidak mengerti rekursi? (perhatikan perbedaannya dari "programmer mana pun")

Jawaban:

22

Apakah programmer rata-rata memahami rekursi dengan mudah dan karenanya seseorang harus menggunakannya dengan impunitas, atau apakah programmer rata-rata tidak memahami rekursi dengan baik dan seseorang harus menjauh darinya demi produktivitas tim secara keseluruhan?

Saya akan mengatakan bahwa programmer rata-rata memahami rekursi dengan sempurna. Memang, jika programmer telah melakukan gelar di bidang Ilmu Komputer atau Rekayasa Perangkat Lunak itu cukup banyak dijamin. Memang, ada beberapa programmer yang sangat di bawah rata-rata di luar sana, tetapi Anda tidak ingin mereka ada di tim Anda.

Dalam hal ini, perbedaan antara rata-rata dan programmer yang baik adalah mengetahui kapan harus menggunakan rekursi dan kapan tidak. Dan itu tergantung pada masalah yang dipecahkan DAN bahasa yang digunakan untuk menyelesaikannya.

  • Jika Anda menggunakan bahasa pemrograman fungsional, rekursi adalah solusi alami dan efisien untuk berbagai masalah. (Aturan optimasi rekursi ekor!)

  • Jika Anda menggunakan OO atau bahasa prosedural biasa, rekursi bisa jadi tidak efisien dan bisa bermasalah karena stack overflow. Jadi dalam beberapa kasus Anda akan memilih solusi berulang daripada yang rekursif. Namun, dalam kasus lain, solusi rekursif jauh lebih sederhana dan elegan sehingga solusi iteratif (mungkin lebih efisien) akan menjadi solusi yang "terlalu pintar". (Sebagai contoh, jika masalah membutuhkan mundur, membangun atau berjalan pohon / grafik, dll, rekursi seringkali lebih sederhana.)

Stephen C
sumber
1
+1 Untuk komentar rekursi ekor. Seringkali upaya untuk menghapus rekursi berakhir dengan banyak struktur stack dan loop dalam kode Anda, yang secara efektif mereplikasi komponen panggilan-stack.
Orbling
1
@Orbling - itu benar, tetapi tumpukan diimplementasikan menggunakan array atau daftar susunan cenderung lebih scalable daripada tumpukan panggilan thread. Terutama karena tumpukan panggilan thread tidak dapat tumbuh di banyak implementasi bahasa.
Stephen C
Ya, itu adalah masalah abadi desain fungsi rekursif. Lebih banyak masalah bagi perancang bahasa untuk mengatasi daripada programmer, idealnya
Orbling
" Memang, ada beberapa programmer yang sangat di bawah rata-rata di luar sana ": OK, itu harus dikatakan ... Dengan definisi yang sangat setengah dari programmer di luar sana rata-rata dan setengah dari mereka yang "di bawah rata-rata".
Lawrence Dol
@LawrenceDol - Saya belum pernah melihat seseorang mengklaim bahwa "sangat" berarti setengah dari segalanya. Apa sumber Anda untuk definisi Anda? (Ini juga harus ditanyakan, karena kesedihan hanya memiliki nilai apa pun jika berbasis fakta.)
Stephen C
42

Beberapa masalah secara alami bersifat rekursif. Menghasilkan solusi berulang dalam kasus-kasus ini sebenarnya bisa lebih kikuk dan kompleks daripada yang rekursif. Contoh yang baik adalah algoritma apa pun yang perlu melintasi struktur hierarki pohon, yang merupakan tugas yang tidak biasa dalam pemrograman.

TL; versi DR: Tidak.

Tabel Bobby
sumber
9
Sepakat. Akan lebih berbahaya untuk melabeli hal-hal sebagai "berbahaya" dan bertindak ekstrem untuk menghindarinya - yang akan selalu menjadi lebih membingungkan dan sulit dipertahankan untuk terus maju.
heretik
11

Rekursi adalah prinsip dasar dalam sebagian besar bahasa pemrograman fungsional. Iterasi (perulangan) dalam bahasa fungsional biasanya dilakukan melalui rekursi.

Bahasa fungsional telah melihat semacam kebangkitan akhir-akhir ini, karena kebutuhan untuk secara elegan menangani lebih banyak core prosesor; bahasa fungsional membantu mencapai konkurensi semacam ini dengan memberikan cara untuk alasan yang lebih baik tentang program Anda tanpa kerumitan yang terlibat dalam mengunci struktur yang bisa berubah.

Robert Harvey
sumber
+1 Komentar bagus. Meskipun saya tidak yakin "kebangkitan" sepenuhnya benar, atau alasan multi-core. Mereka selalu menjadi paradigma favorit dari mereka yang tahu tentang mereka, tetapi proliferasi mereka ke arus utama tidak pernah hebat. Bahasa fungsional baru saja menjadi lebih utama, akan mengambil seluruh utas untuk membahas masalah itu. ( programmers.stackexchange.com/questions/20036/… yang sudah Anda baca)
Orbling
11

Beberapa masalah, seperti berjalan struktur pohon (berjalan, katakanlah, seluruh struktur direktori, berlawanan dengan, katakanlah, mencari node B-Tree tertentu), sangat cocok untuk menggunakan rekursi; padanan non-rekursif sering hanya menambah kerumitan mengelola tumpukan Anda sendiri.

Dalam kasus ini, rekursi adalah solusi terbaik, paling sederhana dan termudah untuk dipahami.

Lawrence Dol
sumber
7

Saya akan mengatakan menggunakan rekursi yang sesuai, tetapi selalu mencari cara untuk menghindari rekursi eksplisit.

Misalnya, jika Anda menemukan kebutuhan untuk secara manual melintasi struktur pohon, maka ya, Anda harus menggunakan rekursi. Jika seseorang cukup bodoh untuk tidak memahami traversal pohon rekursif, mereka tidak akan membuat kepala atau ekor dari versi iteratif.

Tetapi pilihan yang lebih baik adalah menggunakan iterator yang mengabstraksi rekursi ke titik di mana semua yang Anda lihat adalah "Saya melakukan operasi ini pada semua yang ada di pohon".

Segera.
sumber
1
Benar (dan +1), tetapi, tentu saja, seseorang harus menulis abstraksi.
Lawrence Dol
1
Seperti yang dikatakan @Software Monkey, biasanya masih harus dikodekan secara rekursif, tetapi abstraksi ke iterator untuk "penggunaan" tidak masalah.
Orbling
1
Memberi +1 untuk poin bahwa seseorang yang tidak akan memahami versi rekursif kemungkinan besar tidak akan memahami versi berulang. Sayangnya, orang itu juga tidak menyadari bahwa ia tidak memahami versi berulang.
Larry Coleman
3

Rekursi, adalah mekanisme paling sederhana dari sudut pandang kebersihan kode. Jika kecepatan mutlak dari esensi, maka mungkin Anda dapat menggunakan array 2D dari parameter masalah. Memunculkan proses anak kemudian hanya menambahkan item lain ke array. Saya pernah melakukan solver tridiagonal assembler, itu adalah masalah besar pada hari itu. Konteks yang dibutuhkan per instance adalah 8 kata per level, dan masing-masing sub-masalah adalah sepertiga ukuran sebelumnya. "Perpustakaan" ini hanya populer karena mengalahkan semua implementasi lain di luar sana. Tapi, itu situasi yang cukup langka dalam pemrograman, jadi Anda tidak perlu menyerah pada "optimasi prematur", hanya karena solusi ini tersedia. Tentunya untuk beberapa hal itu memerlukan kerja keras yang mengerikan, seperti contoh rekursi "menghitung faktorial". Tetapi untuk sebagian besar aplikasi,

Saya memiliki pemeriksa ejaan sederhana yang saya gunakan untuk aplikasi, (di mana saya ingin memberikan petunjuk tentang memperbaiki kesalahan ejaan kecil), di mana saya menghitung "jarak" antara dua string, yang memungkinkan penghapusan dan penambahan diizinkan. Ini mengarah ke struktur pohon yang berpotensi besar, dan cabang-cabangnya dipangkas karena kami hanya peduli dengan pasangan yang dekat. Dengan rekursi, mungkin dua puluh baris kode (saya memiliki versi Fortran dan C). Saya pikir itu akan berantakan kalau tidak. Heck itu jauh lebih mudah untuk program / debug verifikasi, daripada memikirkan pohon itu!

Omega Centauri
sumber
0

Saya memahaminya tetapi saya tidak pernah secara eksplisit menggunakannya. Saya pikir siapa pun yang menyebut diri mereka seorang programmer harus tahu atau belajar apa itu sebanyak yang mereka perlu tahu apa tumpukan dan tumpukan itu. Hei, semua orang perlu tahu cara kerja min / max di tic-tac-toe, melalui rekursi mewah.

johnny
sumber