Ada beberapa jawaban yang sangat bagus. Saya akan mencoba berkontribusi dalam diskusi.
Pada topik deklaratif, pemrograman logika dalam Prolog, ada buku bagus "The Craft of Prolog" oleh Richard O'Keefe . Ini adalah tentang menulis program yang efisien menggunakan bahasa pemrograman yang memungkinkan Anda menulis program yang sangat tidak efisien. Dalam buku ini, ketika membahas implementasi efisien dari beberapa algoritma (dalam bab "Metode Pemrograman"), penulis mengambil pendekatan berikut:
- mendefinisikan masalah dalam bahasa Inggris
- menulis solusi kerja yang deklaratif mungkin; biasanya, itu berarti apa yang Anda miliki dalam pertanyaan, cukup perbaiki Prolog
- dari sana, ambil langkah untuk memperbaiki implementasi agar lebih cepat
Pengamatan yang paling mencerahkan (untuk saya) yang saya dapat lakukan sambil bekerja melalui ini:
Ya, versi terakhir dari implementasi jauh lebih efisien daripada spesifikasi "deklaratif" yang dimulai oleh penulis. Itu masih sangat deklaratif, ringkas, dan mudah dimengerti. Apa yang terjadi di antaranya adalah bahwa solusi akhir menangkap sifat-sifat masalah yang tidak diketahui oleh solusi awal.
Dengan kata lain, saat mengimplementasikan solusi, kami telah menggunakan sebanyak mungkin pengetahuan kami tentang masalah yang kami bisa. Membandingkan:
Temukan permutasi daftar sehingga semua elemen dalam urutan menaik
untuk:
Menggabungkan dua daftar yang diurutkan akan menghasilkan daftar yang diurutkan. Karena mungkin ada sublist yang sudah disortir, gunakan ini sebagai titik awal, bukan sub daftar panjang 1.
Selain kecil: definisi seperti yang Anda berikan menarik karena sangat umum. Namun, saya tidak bisa lepas dari perasaan bahwa itu sengaja mengabaikan fakta bahwa permutasi adalah masalah kombinatorial. Ini adalah sesuatu yang sudah kita ketahui ! Ini bukan kritik, hanya pengamatan.
Adapun pertanyaan sebenarnya: bagaimana cara bergerak maju? Nah, salah satu caranya adalah memberikan sebanyak mungkin pengetahuan tentang masalah yang kita nyatakan ke komputer.
Upaya terbaik yang saya tahu untuk benar-benar menyelesaikan masalah disajikan dalam buku-buku yang ditulis bersama oleh Alexander Stepanov, "Elemen Pemrograman" dan "Dari Matematika ke Pemrograman Generik" . Saya sedih tidak sampai pada tugas meringkas (atau bahkan sepenuhnya memahami) segala sesuatu dalam buku-buku ini. Namun, pendekatan yang ada untuk mendefinisikan algoritma perpustakaan dan struktur data yang efisien (atau bahkan optimal), di bawah ketentuan bahwa semua properti input yang relevan diketahui sebelumnya. Hasil akhirnya adalah:
- Setiap transformasi yang terdefinisi dengan baik adalah penyempurnaan dari kendala yang sudah ada (properti yang diketahui);
- Kami membiarkan komputer memutuskan transformasi mana yang optimal berdasarkan kendala yang ada.
Mengenai mengapa hal itu belum terjadi, yah, ilmu komputer adalah bidang yang benar-benar muda, dan kami masih berusaha untuk benar-benar menghargai kebaruan sebagian besar darinya.
PS
Untuk memberi Anda gambaran tentang apa yang saya maksud dengan "memperbaiki implementasi": ambil contoh masalah mudah untuk mendapatkan elemen terakhir dari daftar, di Prolog. Solusi deklaratif kanonik adalah dengan mengatakan:
last(List, Last) :-
append(_, [Last], List).
Di sini, makna deklaratif dari append/3
adalah:
List1AndList2
adalah gabungan dari List1
danList2
Karena dalam argumen kedua untuk append/3
kita memiliki daftar dengan hanya satu elemen, dan argumen pertama diabaikan (garis bawah), kita mendapatkan pemisahan dari daftar asli yang membuang bagian depan daftar ( List1
dalam konteks append/3
) dan menuntut agar bagian belakang ( List2
dalam konteks append/3
) memang daftar dengan hanya satu elemen: jadi, itu adalah elemen terakhir.
The aktual implementasi disediakan oleh SWI-Prolog , bagaimanapun, mengatakan:
last([X|Xs], Last) :-
last_(Xs, X, Last).
last_([], Last, Last).
last_([X|Xs], _, Last) :-
last_(Xs, X, Last).
Ini masih deklaratif dengan baik. Baca dari atas ke bawah, katanya:
Elemen terakhir dari daftar hanya masuk akal untuk daftar setidaknya satu elemen. Elemen terakhir untuk sepasang ekor dan kepala daftar adalah: kepala, ketika ekor kosong, atau yang terakhir dari ekor tidak kosong.
Alasan mengapa implementasi ini disediakan adalah untuk mengatasi masalah-masalah praktis seputar model pelaksanaan Prolog. Idealnya, itu seharusnya tidak membuat perbedaan implementasi yang digunakan. Demikian pula, kita dapat mengatakan:
last(List, Last) :-
reverse(List, [Last|_]).
Elemen terakhir dari daftar adalah elemen pertama dari daftar terbalik.
Jika Anda ingin mengisi diskusi tidak meyakinkan tentang apa yang baik, Prolog deklaratif, cukup tanyakan beberapa pertanyaan dan jawaban di tag Prolog pada Stack Overflow .