Tidak ada kekurangan pertanyaan "Skema vs Common Lisp" yang tidak jelas di StackOverflow dan di situs ini, jadi saya ingin membuat yang satu ini lebih fokus. Pertanyaannya adalah untuk orang yang memiliki kode dalam kedua bahasa:
Saat melakukan coding dalam Skema, elemen spesifik apa dari pengalaman coding Common Lisp Anda yang paling Anda lewatkan? Atau, sebaliknya, saat melakukan koding di Common Lisp, apa yang Anda lewatkan dari pengkodean di Skema?
Maksud saya bukan hanya fitur bahasa. Berikut ini adalah semua hal yang valid untuk dilewatkan, sejauh menyangkut pertanyaan:
- Perpustakaan tertentu.
- Fitur spesifik dari lingkungan pengembangan seperti SLIME, DrRacket, dll.
- Fitur implementasi tertentu, seperti kemampuan Gambit untuk menulis blok kode C langsung ke sumber Skema Anda.
- Dan tentu saja, fitur bahasa.
Contoh jenis jawaban yang saya harapkan:
- "Aku sedang mencoba menerapkan X di Common Lisp, dan jika aku memiliki kelanjutan kelas satu Skema, aku benar-benar hanya akan melakukan Y, tetapi sebaliknya aku harus melakukan Z, yang lebih menyebalkan."
- "Membuat skrip proses pembangunan dalam proyek Skema saya menjadi semakin menyakitkan ketika pohon sumber saya tumbuh dan saya terhubung di perpustakaan C. semakin banyak. Untuk proyek berikutnya, saya pindah kembali ke Common Lisp."
- "Saya memiliki basis kode C ++ besar yang sudah ada, dan bagi saya, dapat menyematkan panggilan C ++ secara langsung dalam kode Skema Gambit saya benar-benar bernilai segala kekurangan yang mungkin dimiliki Skema vs Common Lisp, bahkan termasuk kurangnya dukungan SWIG."
Jadi, saya berharap cerita perang, daripada sentimen umum seperti "Skema adalah bahasa yang lebih sederhana" dll.
Jawaban:
Gelar sarjana saya adalah Ilmu Kognitif dan Kecerdasan Buatan. Dari situ saya punya intro satu arah ke Lisp. Saya pikir bahasanya menarik (seperti dalam "elegan") tetapi tidak terlalu memikirkannya sampai saya menemukan Peraturan Kesepuluh Greenspun jauh kemudian:
Poin Greenspun adalah (sebagian) bahwa banyak program kompleks memiliki penafsir bawaan. Daripada membangun penerjemah menjadi bahasa yang ia sarankan, mungkin lebih masuk akal untuk menggunakan bahasa seperti Lisp yang sudah memiliki interpreter (atau kompiler) bawaan.
Pada saat itu saya sedang mengerjakan aplikasi yang agak besar yang melakukan perhitungan yang ditentukan pengguna menggunakan penerjemah khusus untuk bahasa khusus. Saya memutuskan untuk mencoba menulis kembali intinya di Lisp sebagai percobaan skala besar.
Butuh sekitar enam minggu. Kode asli adalah ~ 100.000 baris Delphi (varian Pascal). Di Lisp dikurangi menjadi ~ 10.000 baris. Yang lebih mengejutkan adalah fakta bahwa mesin Lisp 3-6 kali lebih cepat. Dan perlu diingat bahwa ini adalah karya seorang Lisp neophyte! Seluruh pengalaman itu cukup membuka mata saya; untuk pertama kalinya saya melihat kemungkinan menggabungkan kinerja dan ekspresif dalam satu bahasa.
Beberapa waktu kemudian ketika saya mulai mengerjakan proyek berbasis web saya mengikuti audisi sejumlah bahasa. Saya memasukkan Lisp dan Skema ke dalam campuran. Pada akhirnya saya memilih implementasi Skema-- Skema Chez . Saya sangat senang dengan hasilnya.
Proyek berbasis web adalah "mesin seleksi" berkinerja tinggi . Kami menggunakan Skema dalam sejumlah cara berbeda, mulai dari pemrosesan data hingga permintaan data hingga pembuatan halaman. Di banyak tempat kami sebenarnya memulai dengan bahasa yang berbeda tetapi akhirnya bermigrasi ke Skema karena alasan yang akan saya jelaskan secara singkat di bawah ini.
Sekarang saya dapat menjawab pertanyaan Anda (setidaknya sebagian).
Selama audisi kami melihat berbagai implementasi Lisp dan Skema. Di sisi Lisp kami melihat (saya percaya) Allegro CL, CMUCL, SBCL dan LispWorks. Di sisi Skema kami melihat (saya percaya) Bigloo, Chicken, Chez, Gambit. (Pemilihan bahasa sudah lama sekali; itu sebabnya saya agak kabur. Saya bisa menggali beberapa catatan jika itu penting.)
Langsung dari kelelawar kami sedang mencari a) utas asli dan b) dukungan Linux, Mac dan Windows. Gabungan kedua kondisi tersebut membuat semua orang tertekan, tetapi (saya pikir) Allegro dan Chez keluar - jadi untuk melanjutkan evaluasi kami harus melonggarkan persyaratan multi-threading.
Kami mengumpulkan serangkaian program kecil dan menggunakannya untuk evaluasi dan pengujian. Itu mengungkapkan sejumlah masalah. Sebagai contoh: beberapa implementasi memiliki cacat yang mencegah beberapa tes dari berjalan sampai selesai; beberapa implementasi tidak dapat mengkompilasi kode pada saat run-time; beberapa implementasi tidak dapat dengan mudah mengintegrasikan kode kompilasi run-time dengan kode pra-kompilasi; beberapa implementasi memiliki pemulung yang jelas lebih baik (atau jelas lebih buruk) daripada yang lain; dll.
Untuk kebutuhan kami, hanya tiga implementasi komersial - Allegro, Chez dan Lispworks - yang lulus tes utama kami. Dari ketiganya hanya Chez yang lulus semua tes dengan warna terbang. Pada saat itu saya pikir Lispworks tidak memiliki utas asli pada platform apa pun (saya pikir mereka lakukan sekarang) dan saya pikir Allegro hanya memiliki utas asli pada beberapa platform. Selain itu, Allegro memiliki biaya lisensi run-time "hubungi kami" yang sangat saya sukai. Saya percaya Lispworks tidak memiliki biaya run-time dan Chez memiliki pengaturan langsung (dan sangat masuk akal) (dan itu hanya menendang jika Anda menggunakan kompiler saat run-time).
Setelah menghasilkan potongan kode yang agak signifikan di Lisp dan Scheme, berikut adalah beberapa titik perbandingan dan kontras:
Lingkungan Lisp jauh lebih matang. Anda mendapatkan banyak bang untuk uang. (Karena itu, lebih banyak kode juga sama dengan lebih banyak bug.)
Lingkungan Lisp jauh lebih sulit untuk dipelajari. Anda membutuhkan lebih banyak waktu untuk menjadi mahir; Common Lisp adalah bahasa yang sangat besar - dan itu sebelum Anda sampai ke perpustakaan yang ditambahkan implementasi komersial di atasnya. (Karena itu, kasus sintaksis Skema jauh lebih halus dan rumit daripada hal apa pun di Lisp.)
Lingkungan Lisp bisa jadi agak lebih sulit untuk menghasilkan binari. Anda perlu "mengguncang" gambar Anda untuk menghapus bit yang tidak dibutuhkan, dan jika Anda tidak menjalankan program dengan benar selama proses itu, Anda bisa berakhir dengan kesalahan run-time nanti. . Sebaliknya, dengan Chez kami mengkompilasi file tingkat atas yang mencakup semua file lain yang dibutuhkan dan kami selesai.
Saya katakan sebelumnya bahwa kami akhirnya menggunakan Skema di sejumlah tempat yang pada awalnya tidak kami maksudkan. Mengapa? Saya dapat memikirkan tiga alasan dari atas kepala saya.
Pertama, kami belajar untuk mempercayai Chez (dan pengembangnya, Cadence). Kami banyak bertanya dari alat, dan itu disampaikan secara konsisten. Sebagai contoh, Chez secara historis memiliki sejumlah kecil cacat, dan manajer memorinya sangat, sangat baik.
Kedua, kami belajar untuk mencintai kinerja yang kami dapatkan dari Chez. Kami menggunakan sesuatu yang terasa seperti bahasa scripting - dan kami mendapatkan kecepatan kode asli dari itu. Untuk beberapa hal yang tidak masalah - tetapi tidak pernah sakit, dan kadang-kadang itu banyak membantu.
Ketiga, kami belajar untuk mencintai Skema abstraksi yang bisa diberikan. Ngomong-ngomong, saya tidak hanya bermaksud makro; Maksud saya hal-hal seperti penutupan, lambda, panggilan ekor, dll. Begitu Anda mulai berpikir dalam istilah-istilah itu, bahasa lain tampaknya agak terbatas dengan perbandingan.
Apakah Skema sempurna? Tidak; itu adalah trade-off. Pertama, ini memungkinkan masing-masing pengembang menjadi lebih efektif - tetapi lebih sulit bagi pengembang untuk saling memahami kode masing-masing karena rambu-rambu yang dimiliki sebagian besar bahasa (misalnya untuk loop) tidak ada dalam Skema (misalnya, ada sejuta cara untuk melakukan a for loop). Kedua, ada sekelompok pengembang yang jauh lebih kecil untuk diajak bicara, disewa, dipinjam, dll.
Singkatnya, saya pikir saya akan mengatakan: Lisp dan Skema menawarkan beberapa kemampuan yang tidak tersedia secara luas di tempat lain. Kemampuan itu adalah trade-off, jadi sebaiknya itu yang masuk akal dalam kasus khusus Anda. Dalam kasus kami, faktor-faktor penentu antara apakah akan menggunakan Lisp atau Skema lebih terkait dengan fitur-fitur yang sangat mendasar (dukungan platform, utas platform, kompilasi run-time, lisensi run-time) dibandingkan dengan fitur-fitur bahasa atau perpustakaan. Sekali lagi, dalam kasus kami itu juga merupakan trade-off: dengan Chez kami mendapatkan fitur inti yang kami inginkan tetapi kami kehilangan perpustakaan luas yang dimiliki lingkungan Lisp komersial.
Juga, hanya untuk mengulangi: kami telah melihat berbagai Lisps dan Skema sejak lama; mereka semua telah berevolusi dan membaik sejak saat itu.
sumber
Saya biasanya tidak suka menempelkan tautan sebagai jawaban, tetapi saya menulis artikel blog tentang hal ini. Ini tidak lengkap, tetapi mendapat beberapa poin utama.
http://symbo1ics.com/blog/?p=729
Sunting : Berikut adalah poin-poin prinsipnya:
TERPRI
,,PROGN
dll. Skema biasanya memiliki nama yang sangat masuk akal. Ini adalah sesuatu yang terlewatkan dalam CL.list
" menjadi "lst
" dalam Skema.syntax-rules
semuanya baik-baik saja dan keren sampai Anda ingin benar-benar meretas beberapa hal. Di sisi lain, makro higienis kadang-kadang terlewatkan dalam CL. Tidak memiliki cara standar untuk melakukannya berarti menciptakan kembali roda.Walaupun saya hanya berbicara sebagai orang pertama sedikit di atas, harus jelas apa yang saya lewatkan dan apa yang tidak saya lakukan.
[Saya minta maaf jika ini terlalu umum. Sepertinya Anda mungkin menginginkan detail yang lebih spesifik. Ada beberapa spesifik di pos.]
sumber
Saya baru-baru ini memulai proyek rumah menggunakan perpustakaan yang memiliki versi C dan versi Java. Saya ingin menggunakan Lisp untuk proyek tersebut, dan saya menghabiskan sekitar satu bulan bimbang antara menggunakan Common Lisp, Skema atau Clojure. Saya memiliki beberapa pengalaman dengan ketiganya, tetapi hanya proyek mainan. Saya akan menceritakan sedikit tentang pengalaman saya dengan masing-masing dari mereka sebelum memberi tahu Anda mana yang akhirnya saya pilih.
PLT Racket memiliki IDE yang bagus yang tidak hanya memungkinkan Anda mengevaluasi ekspresi dari editor, tetapi juga memungkinkan Anda mengetikkan tanda kurung alih-alih parens, mengubahnya kembali ke parens yang sesuai. Racket juga memiliki satu set perpustakaan besar dengan instalasi dan bahkan lebih banyak tersedia untuk diunduh. Visual debugger juga bermanfaat.
Implementasi Common Lisp (SBCL) saya tidak memiliki IDE, tetapi biasanya dengan implementasi CL open-source untuk menggunakan Emacs dan SLIME. Kombinasi ini bisa sangat efisien. Seiring dengan kemampuan untuk mengevaluasi ekspresi saat Anda mengetikkannya ke file sumber, ada juga REPL yang memiliki semua perintah pengeditan emacs, sehingga penyalinan kode dapat berjalan dengan efisien dua arah. Bahkan objek yang ditampilkan dalam buffer REPL dapat disalin dan ditempelkan.
Alt+(
danAlt+)
efisien untuk berurusan dengan tanda kurung dan indentasi yang cocok.Semua fitur Emacs di atas juga tersedia untuk Clojure. Pengalaman mengedit saya dengan Clojure mirip dengan Lisp. Java interop bekerja dengan baik, dan saya ingin melakukan proyek Clojure begitu matang.
Saya dapat mengakses perpustakaan menggunakan ketiganya (Common Lisp, Racket, dan Clojure), tetapi saya akhirnya memilih Common Lisp untuk proyek tersebut. Faktor penentu adalah bahwa FFI lebih mudah digunakan di Common Lisp. CFFI memiliki manual yang sangat baik dengan kode contoh dan penjelasan terperinci dari setiap metode. Saya bisa membungkus 20 fungsi C dalam satu sore dan tidak harus menyentuh kode sejak itu.
Faktor lainnya adalah bahwa saya lebih akrab dengan Common Lisp daripada dengan Clojure atau Skema R6RS. Saya telah membaca sebagian besar buku-buku Praktis Common Lisp dan Graham, dan saya merasa nyaman dengan Hyperspec. Ini bukan kode "lispy", tapi saya yakin itu akan berubah saat saya mendapatkan lebih banyak pengalaman.
sumber
Saya memprogram CL dan Racket.
Saya sedang mengembangkan situs Web sekarang di Common Lisp, dan saya menulis serangkaian program in-house untuk majikan saya sebelumnya di Racket.
Untuk kode in-house, saya memilih Racket (kemudian dikenal sebagai Skema PLT) karena majikannya adalah toko Windows, dan saya tidak bisa membuat mereka membayar LispWorks. Satu-satunya yang baik open source implementasi CL untuk Windows adalah (dan masih) CCL, yang membutuhkan dukungan SSE dalam prosesor. Majikannya, karena murah, menggunakan perangkat keras Zaman Batu. Bahkan jika majikan memiliki perangkat keras yang layak, satu-satunya pustaka GUI yang berakibat pada Common Lisp adalah McCLIM, yang hanya berfungsi pada Unix. Racket memiliki pustaka GUI yang bagus yang berfungsi pada Unix dan Windows, yang sangat penting untuk kesuksesan proyek saya.
Saya menghabiskan lebih dari setahun memasang dengan editor DrRacket primitif. EMACS tidak bisa mengubah versi GUI dari Racket, yang kemudian dikenal sebagai MrEd, menjadi inferior-lisp di Windows. Saya harus melakukannya tanpa dapat mengevaluasi ekspresi pada kursor dengan satu penekanan tombol. Sebagai gantinya, saya harus secara manual memilih ekspresi S, menyalinnya, klik pada jendela REPL (karena tidak ada penekanan tombol untuk beralih ke itu), lalu tempelkan ekspresi S. Saya juga harus melakukannya tanpa editor yang bisa menunjukkan kepada saya argumen yang diharapkan dari fungsi atau makro yang saya gunakan. DrRacket bukan pengganti SLIME.
Majikan menggunakan database berpemilik dengan XML API yang rumit yang membutuhkan banyak informasi yang tampaknya tidak perlu untuk dapat menanggapi versi kueri SELECT versi. Saya memutuskan untuk menggunakan HTMLPrag baik untuk memancarkan XML ke API ini, dan untuk mem-parsing tanggapan. Itu bekerja dengan baik.
Saya harus mempelajari sistem makro "sintaks kasus" Racket yang terlalu rumit untuk menulis makro yang memungkinkan saya berinteraksi dengan XML API yang terlalu rumit dengan mengetikkan formulir yang tampak seperti SQL. Bagian ini akan jauh lebih mudah jika saya memiliki DEFMACRO yang saya miliki. Namun, hasil akhirnya masih mulus meskipun butuh upaya lebih untuk mencapainya.
Selain itu, saya harus melakukannya tanpa makro Common Lisp LOOP. Racket mulai memberikan alternatif hanya setelah saya menulis sebagian besar kode, dan alternatif itu masih menyebalkan dibandingkan dengan LOOP (meskipun tim pengembangan Racket bersikeras itu lebih baik - mereka salah). Saya akhirnya menulis banyak nama LET form yang menggunakan "mobil" dan "cdr" untuk beralih pada daftar.
Berbicara tentang mobil dan cdr, tidak ada yang lebih membuat frustrasi daripada interpretasi Skema tentang (mobil '()) sebagai kesalahan. Saya mengambil keuntungan dari sensitivitas case Racket dan mengimplementasikan CAR dan CDR, yang memiliki semantik Common Lisp. Namun, pemisahan '() dan #f membuatnya jauh lebih tidak berguna untuk mengembalikan' () sebagai nilai default.
Saya juga akhirnya menerapkan kembali UNWIND-PROTECT, dan menemukan sistem restart saya sendiri untuk mengisi celah yang ditinggalkan oleh Racket. Komunitas Racket perlu belajar bahwa memulai ulang sangat berguna, dan mudah diterapkan.
Formulir nilai-nilai Racket terlalu bertele-tele, jadi saya menerapkan MULTIPLE-VALUE-BIND. Ini benar-benar diperlukan, karena Racket mengharuskan Anda untuk menerima semua nilai yang dihasilkan, apakah Anda menggunakannya atau tidak.
Kemudian, saya mencoba untuk menulis klien eBay XML API di Common Lisp, hanya untuk menemukan bahwa ia tidak memiliki apa pun seperti HTMLPrag. HTMLPrag berguna. Saya akhirnya melakukan proyek itu di Racket. Saya bereksperimen dengan fasilitas Programing Literate Racket, hanya untuk menemukan bahwa saya satu-satunya programmer di Bumi yang menemukan kode literasi yang ditulis dengan benar lebih sulit untuk diedit daripada kode biasa, atau kode literat "komentar berlebihan" yang ditulis dengan tidak tepat.
Proyek baru saya sedang dilakukan di Common Lisp, yang merupakan pilihan yang tepat karena komunitas Racket tidak percaya pada paralelisme, yang sangat penting untuk proyek ini. Satu-satunya hal yang saya pikir telah saya lewatkan dari Racket adalah kelanjutan. Namun, saya dapat melakukan apa yang saya butuhkan dengan menggunakan restart, dan, kalau dipikir-pikir, mungkin bisa melakukannya dengan penutupan sederhana.
sumber
cond
formulir, misalnya) dan bug (apakah saya menulis tes terminasi loop dengan benar saat itu?) Bahkan hari ini, saya mendapatkan kesan bahwa Racket terutama ditujukan untuk siswa dan bukan programmer profesional. Setiap kali saya mendengar seseorang selain saya menggunakannya, mereka menggunakan subbahasa "Siswa Awal" dan itu untuk kelas.Skema dirancang dengan kompilasi terpisah dalam pikiran. Sebagai akibatnya, kekuatan makro-makronya seringkali sangat terbatas, bahkan dengan ekstensi yang memungkinkan defmacro gaya Lisp Umum alih-alih miskin, membatasi sistem makro higienis. Tidak selalu mungkin untuk mendefinisikan makro yang mendefinisikan makro lain, yang dimaksudkan untuk segera digunakan dalam baris kode berikutnya. Dan kemungkinan seperti itu sangat penting untuk mengimplementasikan penyusun eDSL yang efisien.
Tidak perlu disebutkan bahwa implementasi Skema dengan hanya makro higienis R5RS hampir tidak berguna bagi saya, karena gaya pemrograman saya tidak dapat diterjemahkan secara memadai ke dalam kebersihan.
Untungnya, ada implementasi Skema (mis., Racket) yang tidak memiliki batasan itu.
sumber