Pertama, izinkan saya memuji Anda atas ikon pw0n1e Anda yang bagus.
Ini adalah pertanyaan yang sulit untuk dijawab, terutama karena ada begitu banyak varian dari miniKanren dan Prolog. miniKanren dan Prolog sebenarnya adalah rumpun bahasa, yang membuatnya sulit untuk membandingkan fitur-fiturnya, atau bahkan bagaimana keduanya digunakan dalam praktik. Karena itu, harap perhatikan semua yang akan saya katakan dengan hati-hati: jika saya mengatakan bahwa Prolog menggunakan pencarian pertama yang mendalam, ketahuilah bahwa banyak implementasi Prolog mendukung strategi pencarian lain, dan bahwa strategi pencarian alternatif juga dapat dikodekan di meta tingkat penerjemah. Meski begitu, miniKanren dan Prolog memiliki filosofi desain yang berbeda, dan membuat pertukaran yang berbeda.
Prolog adalah salah satu dari dua bahasa klasik untuk pemrograman kecerdasan buatan simbolik (bahasa klasik lainnya adalah Lisp). Prolog unggul dalam mengimplementasikan sistem berbasis aturan simbolik di mana pengetahuan deklaratif dikodekan dalam logika orde pertama. Bahasa ini dioptimalkan untuk ekspresif dan efisiensi untuk jenis aplikasi ini, terkadang dengan mengorbankan kemurnian logis. Misalnya, secara default Prolog tidak menggunakan "pemeriksaan terjadi" dalam penyatuan. Dari sudut pandang matematika / logika, versi penyatuan ini salah. Namun, pemeriksaan terjadi mahal, dan dalam banyak kasus kurangnya pemeriksaan terjadi tidak menjadi masalah. Ini adalah keputusan desain yang sangat pragmatis, seperti penggunaan pencarian mendalam-pertama Prolog, dan penggunaan cut (!
) untuk mengontrol kemunduran. Saya yakin keputusan ini mutlak diperlukan saat menjalankan perangkat keras tahun 1970-an, dan saat ini sangat berguna saat menangani masalah besar, dan saat menangani ruang pencarian yang besar (seringkali tak terbatas!).
Prolog mendukung banyak fitur "ekstra-logis" atau "non-logis", termasuk pemotongan, assert
dan retract
, proyeksi variabel untuk penggunaan aritmatikais
, Dan seterusnya. Banyak dari fitur ini memudahkan untuk mengekspresikan aliran kontrol yang kompleks, dan untuk memanipulasi database fakta global Prolog. Salah satu fitur yang sangat menarik dari Prolog adalah kode Prolog itu sendiri disimpan dalam basis data fakta global, dan dapat ditanyakan pada saat dijalankan. Ini membuatnya mudah untuk menulis meta-interpreter yang mengubah perilaku kode Prolog di bawah interpretasi. Misalnya, dimungkinkan untuk menyandikan pencarian luas-pertama di Prolog menggunakan meta-interpreter yang mengubah urutan pencarian. Ini adalah teknik yang sangat kuat yang tidak dikenal di luar dunia Prolog. 'The Art of Prolog' menjelaskan teknik ini secara rinci.
Upaya luar biasa telah dilakukan untuk meningkatkan implementasi Prolog, yang sebagian besar didasarkan pada Warren Abstract Machine (WAM). WAM menggunakan model efek samping di mana nilai-nilai secara destruktif ditetapkan ke variabel logika, dengan efek samping ini dibatalkan saat dilacak kembali. Banyak fitur yang dapat ditambahkan ke Prolog dengan memperluas instruksi WAM. Satu kelemahan dari pendekatan ini adalah bahwa makalah implementasi Prolog mungkin sulit dibaca tanpa pemahaman yang kuat tentang WAM. Di sisi lain, pelaksana Prolog memiliki model yang sama untuk membahas masalah implementasi. Telah ada banyak penelitian dalam Prolog paralel, yang berpuncak pada Andorra Prolog pada tahun 1990-an. Setidaknya beberapa dari ide ini terus hidup di Ciao Prolog. (Ciao Prolog penuh dengan ide menarik, banyak di antaranya jauh melampaui standar Prolog.)
Prolog memiliki sintaks gaya "pencocokan pola" berbasis penyatuan yang indah yang menghasilkan program yang sangat ringkas. Prologers menyukai sintaks mereka, sama seperti Lisper menyukai ekspresi-s mereka. Prolog juga memiliki pustaka predikat standar yang besar. Karena semua teknik yang telah digunakan untuk membuat WAM cepat, ada implementasi Prolog yang sangat mumpuni dan matang. Hasilnya, banyak sistem berbasis pengetahuan besar telah ditulis seluruhnya di Prolog.
miniKanren dirancang sebagai bahasa pemrograman logika minimal, dengan implementasi yang kecil, mudah dimengerti, dan mudah diretas. miniKanren awalnya tertanam dalam Skema, dan telah di-porting ke lusinan bahasa host lainnya selama dekade terakhir. Implementasi miniKanren yang paling populer adalah 'core.logic' di Clojure, yang sekarang memiliki banyak ekstensi seperti Prolog dan sejumlah pengoptimalan. Baru-baru ini inti dari implementasi miniKanren telah disederhanakan lebih jauh, menghasilkan "kernel mikro" kecil yang disebut "microKanren." miniKanren kemudian dapat diimplementasikan di atas inti mikroKanren ini. Porting microKanren atau miniKanren ke bahasa host baru telah menjadi latihan standar bagi pemrogram yang mempelajari miniKanren. Hasil dari,
Implementasi standar miniKanren dan microKanren tidak mengandung mutasi atau efek samping lainnya, dengan satu pengecualian: beberapa versi miniKanren menggunakan persamaan pointer untuk perbandingan variabel logika. Saya menganggap ini sebagai "efek jinak", meskipun banyak penerapan bahkan menghindari efek ini dengan melewatkan penghitung melalui penerapan. Juga tidak ada database fakta global. Filosofi implementasi miniKanren terinspirasi oleh pemrograman fungsional: mutasi dan efek harus dihindari, dan semua konstruksi bahasa harus menghormati ruang lingkup leksikal. Jika Anda melihat dengan cermat implementasinya, Anda bahkan mungkin melihat beberapa monad. Implementasi pencarian didasarkan pada penggabungan dan manipulasi aliran lambat, sekali lagi tanpa menggunakan mutasi. Pilihan implementasi ini menghasilkan trade-off yang sangat berbeda dengan di Prolog. Di Prolog, pencarian variabel adalah waktu yang konstan, tetapi pengulangan memerlukan efek samping yang dibatalkan. Dalam pencarian variabel miniKanren lebih mahal, tetapi backtracking "gratis". Faktanya, tidak ada kemunduran di miniKanren, karena cara penanganan aliran.
Salah satu aspek menarik dari implementasi miniKanren adalah bahwa kode tersebut secara inheren aman untuk thread dan - setidaknya dalam teori - dapat diparalelkan secara sepele. Tentu saja, memparalelkan kode tanpa membuatnya lebih lambat bukanlah hal yang sepele, mengingat setiap utas atau proses harus diberikan pekerjaan yang cukup untuk menutupi overhead paralelisasi. Meski demikian, ini adalah bidang implementasi miniKanren yang saya harap akan mendapat perhatian dan eksperimen lebih.
miniKanren menggunakan pemeriksaan terjadi untuk penyatuan, dan menggunakan pencarian interleaving lengkap daripada pencarian kedalaman-pertama. Pencarian interleaving menggunakan lebih banyak memori daripada pencarian mendalam-pertama, tetapi dapat menemukan jawaban dalam beberapa kasus di mana pencarian kedalaman-pertama akan menyimpang / berulang selamanya. miniKanren tidak mendukung operator ekstra-logis --- beberapa conda
, condu
dan project
, misalnya. conda
dan condu
dapat digunakan untuk mensimulasikan potongan Prolog, dan project
dapat digunakan untuk mendapatkan nilai yang terkait dengan variabel logika.
Kehadiran conda
, condu
danproject
--- dan kemampuan untuk dengan mudah mengubah strategi pencarian --- memungkinkan pemrogram untuk menggunakan miniKanren sebagai bahasa mirip Prolog yang disematkan. Ini terutama berlaku untuk pengguna 'core.logic' Clojure, yang menyertakan banyak ekstensi mirip Prolog. Penggunaan miniKanren yang "pragmatis" ini tampaknya merupakan mayoritas dari penggunaan miniKanren dalam industri. Pemrogram yang ingin menambahkan sistem penalaran berbasis pengetahuan ke aplikasi yang sudah ada yang ditulis dalam Clojure atau Python atau JavaScript umumnya tidak tertarik untuk menulis ulang seluruh aplikasi mereka di Prolog. Menyematkan bahasa pemrograman logika kecil di Clojure atau Python jauh lebih menarik. Implementasi Prolog yang disematkan akan bekerja dengan baik untuk tujuan ini, mungkin.
Selain penggunaan miniKanren sebagai bahasa pemrograman logika tertanam pragmatis yang mirip dengan semangat Prolog, miniKanren digunakan untuk penelitian dalam pemrograman "relasional". Artinya, dalam menulis program yang berperilaku sebagai hubungan matematika daripada fungsi matematika. Misalnya, dalam Skema append
fungsi bisa menambahkan dua daftar, mengembalikan daftar baru: panggilan fungsi (append '(a b c) '(d e))
mengembalikan daftar (a b c d e)
. Namun, kita juga bisa memperlakukan append
sebagai relasi tiga tempat daripada sebagai fungsi dua argumen. Panggilan (appendo '(a b c) '(d e) Z)
kemudian akan mengasosiasikan variabel logika Z
dengan daftar (a b c d e)
. Tentu saja hal-hal menjadi lebih menarik ketika kita menempatkan variabel logika di posisi lain. Panggilan (appendo X '(d e) '(a b c d e))
terkait X
dengan (a b c)
, saat panggilan(appendo X Y '(a b c d e))
asosiasi X
dan Y
dengan pasangan daftar yang, jika ditambahkan, sama dengan (a b c d e)
. Misalnya X
= (a b)
dan Y
= (c d e)
adalah salah satu pasangan nilai tersebut. Kami juga dapat menulis (appendo X Y Z)
, yang akan menghasilkan jauh lebih banyak tiga kali lipat dari daftar X
, Y
dan Z
sehingga menambahkan X
untuk Y
menghasilkan Z
.
Versi relasional ini append
dapat dengan mudah diekspresikan dalam Prolog, dan memang ditampilkan di banyak tutorial Prolog. Dalam praktiknya, program Prolog yang lebih kompleks cenderung menggunakan setidaknya beberapa fitur ekstra-logis, seperti cut, yang menghambat kemampuan untuk memperlakukan program yang dihasilkan sebagai relasi. Sebaliknya, miniKanren secara eksplisit dirancang untuk mendukung gaya pemrograman relasional ini. Versi yang lebih baru dari miniKanren memiliki dukungan untuk pemecahan kendala simbolik ( symbolo
, numbero
,absento
, kendala ketidaksetaraan, pemrograman logika nominal) untuk mempermudah penulisan program non-sepele sebagai relasi. Dalam praktiknya saya tidak pernah menggunakan fitur ekstra-logis miniKanren, dan saya menulis semua program miniKanren saya sebagai relasi. Program relasional yang paling menarik adalah interpreter relasional untuk subset Skema. Penerjemah ini memiliki banyak kemampuan menarik, seperti menghasilkan sejuta program Skema yang mengevaluasi daftar (I love you)
, atau menghasilkan quine (program yang mengevaluasi diri mereka sendiri).
miniKanren membuat sejumlah trade-off untuk mengaktifkan gaya pemrograman relasional ini, yang sangat berbeda dari trade-off yang dibuat Prolog. Seiring waktu, miniKanren telah menambahkan lebih banyak batasan simbolis, benar-benar menjadi bahasa Pemrograman Batasan Logika yang berorientasi secara simbolis. Dalam banyak kasus, batasan simbolis ini membuatnya praktis untuk menghindari penggunaan operator ekstra-logis seperti condu
dan project
. Dalam kasus lain, batasan simbolis ini tidak cukup. Dukungan yang lebih baik untuk batasan simbolis adalah salah satu bidang aktif penelitian miniKanren, bersama dengan pertanyaan yang lebih luas tentang bagaimana menulis program yang lebih besar dan lebih kompleks sebagai relasi.
Singkatnya, baik miniKanren maupun Prolog memiliki fitur, implementasi, dan kegunaan yang menarik, dan menurut saya ide-ide dari kedua bahasa itu layak dipelajari. Ada juga bahasa pemrograman logika lain yang sangat menarik, seperti Mercury, Curry, dan Gödel, yang masing-masing memiliki pemrograman logika sendiri.
Saya akan mengakhiri dengan beberapa sumber miniKanren:
Situs web miniKanren utama:
http://minikanren.org/
Wawancara yang saya berikan tentang pemrograman relasional dan miniKanren, termasuk perbandingan dengan Prolog:
http://www.infoq.com/interviews/byrd-relational-programming-minikanren
Bersulang,
--Akan