C # Dev - Saya sudah mencoba Lisps, tapi saya tidak mengerti [ditutup]

37

Setelah beberapa bulan belajar tentang dan bermain dengan Lisp, baik CL dan sedikit Clojure, saya masih belum melihat alasan kuat untuk menulis apa pun di dalamnya daripada C #.

Saya benar-benar ingin beberapa alasan kuat, atau bagi seseorang untuk menunjukkan bahwa saya kehilangan sesuatu yang sangat besar .

Kekuatan Lisp (per penelitian saya):

  • Notasi kompak dan ekspresif - Lebih dari sekadar C #, ya ... tapi saya juga bisa mengekspresikan ide-ide itu dalam C #.
  • Dukungan implisit untuk pemrograman fungsional - C # dengan metode ekstensi LINQ:
    • mapcar = .Pilih (lambda)
    • mapcan = .Select (lambda) .Aregregate ((a, b) => a.Union (b))
    • mobil / pertama = .Pertama ()
    • cdr / rest = .Skip (1) .... dll.
  • Lambda dan dukungan fungsi tingkat tinggi - C # memiliki ini, dan sintaksinya bisa dibilang lebih sederhana:
    • "(lambda (x) (tubuh))" versus "x => (tubuh)"
    • "# (" dengan "%", "% 1", "% 2" bagus di Clojure
  • Metode pengiriman terpisah dari objek - C # memiliki ini melalui metode ekstensi
  • Pengiriman multimethod - C # tidak memiliki ini secara asli, tapi saya bisa mengimplementasikannya sebagai pemanggilan fungsi dalam beberapa jam
  • Code is Data (and Macros) - Mungkin saya belum "mendapatkan" makro, tapi saya belum melihat satu contoh pun di mana gagasan makro tidak dapat diimplementasikan sebagai fungsi; itu tidak mengubah "bahasa", tapi saya tidak yakin itu kekuatan
  • DSL - Hanya dapat melakukannya melalui komposisi fungsi ... tetapi berfungsi
  • Pemrograman "eksplorasi" yang tidak diketik - untuk struct / kelas, properti otomatis dan "objek" C # bekerja cukup baik, dan Anda dapat dengan mudah meningkat menjadi pengetikan yang lebih kuat saat Anda mengikuti
  • Berjalan pada perangkat keras non-Windows - Ya, jadi? Di luar kampus, saya hanya kenal satu orang yang tidak menjalankan Windows di rumah, atau setidaknya VM Windows di * nix / Mac. (Sekali lagi, mungkin ini lebih penting daripada yang saya pikirkan dan saya baru saja dicuci otak ...)
  • REPL untuk desain bottom-up - Ok, saya akui ini benar-benar bagus, dan saya melewatkannya di C #.

Hal yang saya lewatkan di Lisp (karena campuran C #, .NET, Visual Studio, Resharper):

  • Ruang nama. Bahkan dengan metode statis, saya suka mengikat mereka ke "kelas" untuk mengkategorikan konteksnya (tampaknya Clojure memiliki ini, CL sepertinya tidak.)
  • Dukungan kompilasi dan desain-waktu yang hebat
    • sistem tipe memungkinkan saya untuk menentukan "kebenaran" dari struktur data yang saya bagikan
    • sesuatu yang salah eja digarisbawahi secara realtime; Saya tidak perlu menunggu sampai runtime tahu
    • perbaikan kode (seperti menggunakan pendekatan FP bukan yang imperatif) disarankan secara otomatis
  • Alat pengembangan GUI: WinForms dan WPF (saya tahu Clojure memiliki akses ke perpustakaan GUI Java, tetapi semuanya sepenuhnya asing bagi saya.)
  • Alat Debugging GUI: breakpoints, step-in, step-over, pemeriksa nilai (teks, xml, custom), jam tangan, debug-by-thread, breakpoint bersyarat, jendela panggilan-tumpukan dengan kemampuan untuk melompat ke kode di tingkat mana pun di tumpukan
    • (Agar adil, tugas saya dengan Emacs + Slime tampaknya memberikan sebagian dari ini, tapi saya tidak setuju dengan pendekatan yang digerakkan VS GUI)

Saya sangat suka hype di sekitar Lisp dan saya memberikannya kesempatan.

Tetapi adakah yang bisa saya lakukan di Lisp yang tidak bisa saya lakukan dengan baik di C #? Mungkin sedikit lebih verbose di C #, tapi saya juga punya autocomplete.

Apa yang saya lewatkan? Mengapa saya harus menggunakan Clojure / CL?

talonx
sumber
4
Karena Anda sudah memprogram dengan gaya fungsional dan sepertinya Anda sangat bergantung pada infrastruktur Windows, saya tidak dapat melihat alasan kuat untuk Anda ubah dari C #. Hampir semua orang yang saya kenal menggunakan Mac atau Linux, jadi sangat jelas tergantung pada kerumunan yang Anda jalankan (Saya telah menggunakan setiap versi Windows sejak 3.1 tetapi saya masih lebih suka bekerja dengan perangkat lunak lintas platform dan sistem * nix pada umumnya ... tapi kemudian saya tidak melakukan pekerjaan GUI asli, semua server dan hal-hal web UI)
Sean Corfield
2
Anda bisa melihat The Swine Before Perl . Ini adalah pembicaraan yang menyenangkan untuk didengarkan, dan menyajikan contoh sederhana tentang apa yang baik untuk makro.
Matthias Benkard
4
"Saya belum melihat satu contoh pun di mana gagasan makro tidak dapat diimplementasikan sebagai fungsi" - Saya ingin melihat bagaimana Anda akan menulis ANDatau ORsebagai fungsi. Itu bisa dilakukan (diberikan LAMBDA, yang juga makro) tapi saya tidak melihat cara yang jelas untuk melakukannya yang tidak akan benar-benar payah.
1
"Ruang nama. ... Clojure tampaknya memiliki ini, CL sepertinya tidak" - bisakah Anda lebih spesifik tentang apa yang Anda cari? Saya tidak benar-benar menggunakan Clojure tetapi ruang namanya terlihat sangat mirip dengan paket CL.
4
Jonathan: Penggunaan CL :(atau ::untuk simbol yang tidak diekspor) untuk penamaan simbol dalam paket, misalnya, contoh Anda di sini akan menggunakan http:sessiondan chat:session.

Jawaban:

23

Makro memungkinkan Anda menulis kompiler tanpa meninggalkan kenyamanan bahasa Anda. DSL dalam bahasa seperti C # umumnya berjumlah penerjemah runtime. Bergantung pada domain Anda, itu mungkin bermasalah karena alasan kinerja. Kecepatan itu penting , jika tidak Anda akan mengkode dalam bahasa yang ditafsirkan dan bukan C #.

Selain itu, makro juga memungkinkan Anda mempertimbangkan faktor manusia - apa sintaks yang paling mudah digunakan untuk DSL tertentu? Dengan C # tidak banyak yang dapat Anda lakukan tentang sintaks.

Jadi Lisp memungkinkan Anda berpartisipasi dalam desain bahasa tanpa mengorbankan jalan menuju efisiensi . Dan sementara masalah ini mungkin tidak masalah bagi Anda , mereka sangat penting karena mereka mendasari fondasi semua bahasa pemrograman berorientasi produksi yang berguna. Dalam C # elemen dasar ini terpapar kepada Anda dalam bentuk yang sangat terbatas.

Pentingnya makro tidak hilang pada bahasa lain - Template Haskell, camlp4 datang ke pikiran. Tapi sekali lagi ini adalah masalah kegunaan - Lisp macro sampai saat ini kemungkinan merupakan implementasi transformasi waktu kompilasi yang paling ramah pengguna namun kuat.

Jadi, ringkasnya, apa yang umumnya dilakukan orang dengan bahasa seperti C # adalah membangun DSIL (Domain Specific Interpreted Languages). Lisp memberi Anda kesempatan untuk membangun sesuatu yang jauh lebih radikal, DSP (Domain Specific Paradigms). Racket (sebelumnya PLT-Skema) sangat menginspirasi dalam hal ini - mereka memiliki bahasa malas (Lazy Racket), yang diketik (Typed Racket), Prolog, dan Datalog semuanya tertanam secara idiomatis melalui makro. Semua paradigma ini memberikan solusi yang kuat untuk kelas besar masalah - masalah tidak diselesaikan dengan baik oleh pemrograman imperatif atau bahkan paradigma FP.

Robert Harvey
sumber
3
Apa yang saya temukan menarik tentang argumen itu adalah bahwa saya tidak pernah mengalami peluang (atau hanya benar-benar mengabaikannya dalam ketidaktahuan saya) untuk menerapkan DSL / DSIL. Bisakah Anda menguraikan kekuatan DSL? (Untuk pengembang dan pengguna.) Sepertinya ini adalah hal besar yang benar-benar saya lewatkan.
15
@Jonathan Mitchem, Anda sudah menggunakan banyak DSL eksternal - file konfigurasi, skrip bangun, konfigurasi ORM, generator kode visual (mis., Winforms editor), XAML, generator parser, dll. DSL yang tertanam lebih baik lagi, karena Anda tidak akan membutuhkan alat pembuatan terpisah untuk mereka, dan mereka disajikan dalam satu bahasa. Dan Anda harus terbiasa dengan setidaknya dua DSL tertanam - ekspresi reguler dan SQL.
SK-logic
Wow, baiklah. Saya tidak pernah menganggapnya sebagai DSL. Sekarang, saya sengaja menyimpang dari banyak hal, atas dasar "apa pun yang bisa saya lakukan dengan c #, saya akan tetap menggunakan c # for". Saya suka bertahan dengan satu alat dengan perilaku yang konsisten, secara pribadi. Tapi saya mengerti nilai DSL dalam contoh-contoh ini.
2
@ Jonathan Mitchem, masalah dengan alat apa pun yang diberikan adalah tidak perlu cocok untuk tujuan tertentu. Anda harus memilih alat yang berbeda untuk tugas yang berbeda. Dan kekuatan bahasa meta apa pun, termasuk Lisp, adalah Anda tidak harus sepenuhnya beralih ke alat lain, karena Anda dapat menumbuhkan alat khusus domain Anda sendiri di atas bahasa utama Anda. Saya sarankan Anda melihat Nemerle, akan lebih mudah untuk memahaminya untuk pengembang C #, dan makro hampir sama kuatnya dengan Lisp.
SK-logic
3
"Saya suka bertahan dengan satu alat ..." DSL yang dibuat dengan benar di Lisp tidak pernah menyembunyikan kekuatan penuh Lisp, jadi Anda masih memiliki satu alat. Mereka hanya menambah kosakata dengan cara yang membuat pengkodean untuk domain tertentu lebih "alami", yaitu dengan abstraksi yang lebih baik dan organisasi secara keseluruhan.
15

Hampir semua yang semula hanya tersedia di Lisps telah untungnya bermigrasi ke banyak bahasa modern lainnya. Pengecualian terbesar adalah filosofi "kode adalah data", dan makro.

Kode adalah Data (dan Makro) - Mungkin saya belum mendapatkan "makro", tetapi saya belum melihat satu contoh pun di mana gagasan makro tidak dapat diimplementasikan sebagai fungsi

Ya, makro sulit untuk grok. Pemrograman secara umum sulit dilakukan. Jika Anda melihat makro apa pun yang dapat diimplementasikan sebagai fungsi, maka programmer salah melakukannya. Macro seharusnya hanya digunakan ketika suatu fungsi tidak bekerja.

Contoh "hello world" dari makro adalah menulis "jika" dalam hal cond. Jika Anda benar-benar tertarik untuk mempelajari kekuatan makro, cobalah mendefinisikan "my-if" di clojure, menggunakan fungsi, dan perhatikan bagaimana hal itu pecah. Saya tidak bermaksud untuk menjadi misterius, saya hanya belum pernah melihat orang mulai memahami makro dengan penjelasan saja, tapi tayangan slide ini adalah intro yang cukup bagus: http://www.slideshare.net/pcalcado/lisp-macros-in -20-menit-menampilkan-presentasi-clojure

Saya memiliki proyek kecil di mana saya menyimpan ratusan / ribuan baris kode menggunakan makro (dibandingkan dengan apa yang akan diambil di Jawa). Banyak Clojure diimplementasikan di Clojure, yang hanya mungkin karena sistem makro.

mblinn
sumber
3
Tanpa menyentuh kode apa pun, saya menjalankan skenario menerapkan "jika" tanpa makro di kepala saya, baik di Clojure dan C #. Secara efektif (atau secara harfiah) tidak dapat dilakukan. Saya akui itu rapi. Tapi saya kehilangan koneksi tentang bagaimana itu berguna bagi saya. Apa yang bisa saya lakukan dengan makro (selain menulis "jika") yang tidak dapat saya lakukan dengan fungsional pintar atau OO-desain? "Bagaimana ini bisa membantu saya" bukan kriteria yang valid untuk mengevaluasi bahasa, tetapi untuk mengevaluasi apakah saya akan menggunakannya. (Saya benar - benar ingin Lisp layak untuk diganti, tetapi belum mencapai titik untuk menjadi alternatif yang layak.)
1
Saya perlu sedikit waktu untuk menggunakan contoh itu. Bagi saya, "menghemat kode boilerplate" biasanya memanggil istilah "refactoring", yang merupakan bagian dari mengapa penjelasannya belum meyakinkan saya. Saya punya solusi yang berfungsi dalam setiap contoh saya telah menerapkannya. Saya pikir pertanyaannya adalah bagaimana Anda mengidentifikasi kasus di mana Anda dapat menggunakan makro?
1
Saya setuju bahwa makro bermanfaat, tetapi tidak benar bahwa saya-jika memerlukannya, dapat ditulis sebagai fungsi tingkat tinggi (lihat contoh CL di bawah). Anda hanya benar-benar membutuhkan makro jika ingin menjalankan kode atau menempatkannya dalam konteks leksikal baru. (defun my-if (test then &optional else) (cond (test (funcall then)) ('otherwise (funcall else))))
1
Pada dasarnya dengan fungsi Anda memiliki pilihan untuk menerima kode yang dikutip, yang dapat Anda jalani tetapi tidak ada konteks leksikal karena Anda berjalan dan menjalankannya dalam konteks leksikal dari fungsi Anda. Atau Anda dapat menerima penutupan, yang menjaga konteks leksikal mereka tetapi Anda hanya dapat memanggil, tidak memandu mereka atau menambahkan sesuatu ke konteks leksikal mereka. Untuk melakukan keduanya, Anda memerlukan makro, yang dapat berjalan dan membungkus kode sebelum ekspansi akan ditempatkan ke dalam konteks leksikal panggilan makro.
7
@ Jonathan Mitchem, sintaksis LINQ adalah contoh yang bagus dari apa yang dapat dilakukan dengan makro, tetapi harus diimplementasikan dalam inti bahasa sebagai gantinya, karena bahasa tidak mendukung metaprogramming yang layak.
SK-logic
14

Saya bukan ahli Common Lisp, tapi saya tahu C # dan Clojure cukup baik sehingga mudah-mudahan ini adalah perspektif yang berguna.

  • Sintaks sederhana => daya - Lisps adalah tentang sintaksis paling sederhana yang dapat bekerja. S-ekspresi adalah semua yang Anda butuhkan. Setelah Anda grokked "(function-call arg1 arg2 arg3)" maka pada dasarnya Anda sudah mendapatkannya. Sisanya hanya memilih panggilan fungsi dan argumen yang tepat. Tampaknya hampir sepele, tetapi kenyataannya adalah bahwa kesederhanaan inilah yang memberi Lisps begitu banyak kekuatan dan fleksibilitas, dan khususnya memungkinkan kemampuan pemrograman meta yang terkenal dengan Lisp. misalnya jika saya ingin makro memanggil beberapa fungsi berbeda pada argumen yang sama, saya hanya melakukan sesuatu seperti berikut (bukan ini bukan hanya aplikasi fungsi runtime - itu adalah makro yang menghasilkan kode yang dikompilasi seolah-olah Anda telah menuliskan semua panggilan fungsi individual dengan tangan):
(defmacro print-many [functions args]  
  `(do   
     ~@(map   
        (fn [function] `(println (~function ~@args)))   
        functions)))

(print-many [+ - * /] [10 7 2])  
19  
1  
140  
5/7
  • Sebagai hasil dari sintaks yang sangat sederhana, filosofi "code is data" Lisp jauh lebih kuat daripada apa pun yang dapat Anda lakukan dengan komposisi fungsi / templat / generik dll. Ini lebih dari sekadar DSL, pembuatan kode dan manipulasi, pada waktu kompilasi , sebagai fitur dasar bahasa. Jika Anda mencoba untuk mendapatkan kemampuan semacam ini dalam bahasa non- homoiconic seperti C # atau Java, Anda akhirnya akan menemukan kembali Lisp, buruk. Karena itulah Aturan Kesepuluh Greenspuns yang terkenal: "Setiap program C atau Fortran yang cukup rumit mengandung implementasi ad hoc, dispesifikasikan secara informal, ditanggulangi, lambat dari setengah Common Lisp". Jika Anda pernah menemukan diri Anda menciptakan bahasa kontrol templating / flow turing lengkap dalam aplikasi Anda maka Anda mungkin tahu apa yang saya maksud .....

  • Concurrency adalah kekuatan unik Clojure (bahkan relatif terhadap Lisps lain), tetapi jika Anda percaya bahwa masa depan pemrograman akan berarti harus menulis aplikasi yang skala ke mesin yang sangat multi-core, maka Anda benar-benar benar-benar harus melihat ke dalam ini - itu cukup terobosan. Clojure STM (Memori Transaksional Perangkat Lunak) berfungsi karena Clojure mencakup konstruksi ketetapan dan konkurensi bebas-kunci berdasarkan pemisahan baru antara identitas dan negara (lihat video hebat Rich Hickey tentang identitas dan negara ). Akan sangat menyakitkan untuk mencangkokkan kemampuan konkurensi semacam ini ke lingkungan bahasa / runtime di mana sebagian besar API bekerja pada objek yang bisa diubah.

  • Pemrograman fungsional - Lisps menekankan pemrograman dengan fungsi urutan yang lebih tinggi. Anda benar bahwa itu dapat ditiru dalam objek OO dengan objek penutupan / fungsi dll. Tetapi perbedaannya adalah bahwa seluruh bahasa dan pustaka standar dirancang untuk membantu Anda menulis kode dengan cara ini. Sebagai contoh, urutan Clojure adalah malas , jadi bisa sangat lama tidak seperti ArrayLists atau HashMaps Anda di C # / Java. Ini membuat beberapa algoritma lebih mudah untuk diekspresikan, misalnya yang berikut mengimplementasikan daftar angka-angka fibonacci yang tidak terbatas:

    (def fibs (lazy-cat '(0 1) (map + fibs (drop 1 fibs))))

  • Pengetikan dinamis - Lisps cenderung berada di ujung "dinamis" dari spektrum bahasa pemrograman fungsional (berbeda dengan bahasa seperti Haskell dengan konsepsi statis tipe yang sangat kuat dan indah). Ini memiliki kelebihan dan kekurangan, tetapi saya berpendapat bahwa bahasa yang dinamis cenderung mendukung produktivitas pemrograman karena fleksibilitas yang lebih besar. Pengetikan dinamis ini memiliki biaya kinerja runtime kecil, tetapi jika itu mengganggu Anda, Anda selalu dapat menambahkan petunjuk jenis ke kode Anda untuk mendapatkan pengetikan statis. Pada dasarnya - Anda mendapatkan kenyamanan secara default, dan kinerja jika Anda bersedia melakukan sedikit pekerjaan ekstra untuk mendapatkannya.

  • Pengembangan interaktif - sebenarnya saya pikir Anda bisa mendapatkan semacam REPL untuk C # 4.0, tetapi di Lisp itu praktik standar daripada hal yang baru. Anda tidak harus melakukan siklus kompilasi / bangun / uji coba sama sekali - Anda menulis kode Anda langsung di lingkungan yang sedang berjalan, dan hanya kemudian menyalinnya ke file sumber Anda. Ini mengajarkan Anda cara yang sangat berbeda untuk kode, di mana Anda melihat hasilnya segera dan memperbaiki solusi Anda secara iteratif.

Beberapa komentar singkat tentang hal-hal yang Anda lihat "hilang":

  • Seperti yang Anda katakan, Clojure memiliki ruang nama. Bahkan, mereka adalah ruang nama dinamis: Anda dapat memperbaruinya saat runtime - ini memberikan beberapa manfaat yang mengejutkan untuk pengembangan interaktif. Saya telah banyak bersenang-senang mendefinisikan kembali fungsi di bawah hidung thread yang sedang berjalan, atau meretas struktur data langsung ....
  • Kompilasi / dukungan waktu desain - tidak benar-benar relevan jika Anda membuat kode pada REPL - Anda cukup melakukannya dan melihat hasilnya secara langsung. Karena itu, Clojure mulai mendapatkan dukungan IDE yang ditingkatkan, misalnya plugin CounterClockwise untuk Eclipse .
  • Pengembangan GUI - Ya, Anda harus belajar API baru, tapi itu akan selalu menjadi kasus ketika beralih bahasa .... kabar baiknya adalah bahwa API Java tidak begitu sulit dan sekarang ada beberapa Clojure- yang menarik pembungkus / contoh spesifik yang terlihat cukup mudah digunakan. Lihat pertanyaan ini tentang pengembangan GUI Clojure untuk beberapa contoh yang bagus
  • GUI debugging: ini bekerja dengan GUI debugger di Eclipse dengan asumsi Anda menggunakan CounterClockwise, atau Enclojure jika Anda menggunakan Netbeans. Karena itu, saya tidak menggunakan kemampuan ini - saya menemukan debugging interaktif di REPL lebih produktif.

Saya pribadi menemukan keuntungan dari Clojure / Lisp yang cukup menarik, dan saya tidak berencana untuk kembali ke C # / Java (di luar apa yang saya butuhkan untuk meminjam semua perpustakaan yang bermanfaat!).

Namun, butuh beberapa bulan bagi saya untuk benar-benar memahami semuanya. Jika Anda benar-benar tertarik mempelajari Lisp / Clojure sebagai pengalaman belajar yang mencerahkan, tidak ada pengganti untuk menyelam dan memaksa diri Anda untuk menerapkan beberapa hal .....

mikera
sumber
1
Terima kasih untuk enumerasi ide yang hebat. Saya benar-benar menggunakan banyak urutan malas melalui IEnumerable <> construct di C # (dan belum menyentuh ArrayList sejak 2005 atau lebih) tetapi saya mengerti idenya. Konklusi primitif Clojure sangat mengesankan. Saya melakukan komputasi grid di C # beberapa tahun yang lalu - concurrency di banyak mesin multi-core - dan saya masih percaya itu adalah masa depan. Mungkin ide terbesar yang saya dapatkan dari semua orang adalah "Anda benar-benar harus menggali dan mengalaminya, itu tidak bisa dijelaskan". Jadi, saya akan terus menggali dan terus mengalami.
1
Keren, senang bisa membantu - dan itu benar-benar semangat yang tepat !!
mikera
10

C # punya banyak fitur, tetapi campurannya terasa berbeda. Bahwa beberapa bahasa memiliki fitur masih tidak berarti bahwa itu mudah digunakan, paradigmatik dan terintegrasi dengan baik dengan seluruh bahasa.

Common Lisp memiliki campuran ini:

  • s-expressions sebagai sintaksis data
  • kode sebagai data mengarah ke makro dan teknik komputasi simbolik lainnya
  • bahasa dinamis memungkinkan modifikasi runtime (pengikatan lambat, MOP, ...)
  • diketik dengan kuat, diketik secara dinamis
  • penggunaan interaktif dengan kompiler atau juru bahasa tambahan
  • Evaluator sebagai mesin eksekusi inti
  • memori yang dikelola dengan Koleksi Sampah
  • Bahasa hibrid dengan penggunaan pemrograman imperatif, fungsional, dan berorientasi objek yang berat. Paradigma lain dapat ditambahkan (aturan, logika, kendala, ...).

Sekarang, bahasa lain, seperti C #, memilikinya juga. Namun seringkali tidak dengan penekanan yang sama.

C # telah

  • Sintaks seperti C
  • sebagian besar berorientasi objek imperatif, dengan beberapa fitur FP
  • diketik secara statis
  • sebagian besar penggunaan batch dengan kompiler batch
  • memori yang dikelola dengan Koleksi Sampah

Itu tidak membantu bahwa C # memiliki misalnya fitur manipulasi kode, jika mereka tidak banyak digunakan seperti pada Lisp. Di Lisp Anda tidak akan menemukan banyak perangkat lunak yang tidak menggunakan makro dalam berbagai cara sederhana dan kompleks. Menggunakan manipulasi kode benar-benar fitur besar di Lisp. Meniru beberapa penggunaan dimungkinkan dalam banyak bahasa, tetapi itu tidak menjadikannya fitur utama seperti pada Lisp. Lihat buku-buku seperti 'On Lisp' atau 'Practical Common Lisp' untuk contohnya.

Sama untuk pengembangan interaktif. Jika Anda mengembangkan sistem CAD besar, sebagian besar pengembangan akan bersifat interaktif dari editor dan REPL - langsung ke dalam aplikasi CAD yang sedang berjalan. Anda dapat meniru banyak hal itu dalam C # atau bahasa lain - seringkali dengan menerapkan bahasa ekstensi. Untuk Lisp akan bodoh untuk me-restart aplikasi CAD yang sedang dikembangkan untuk menambahkan perubahan. Sistem CAD kemudian juga akan berisi Lisp yang disempurnakan yang akan menambahkan fitur bahasa (dalam bentuk makro dan deskripsi simbolik) untuk menggambarkan objek CAD dan hubungannya (bagian-dari, berisi, ...). Orang dapat melakukan hal serupa di C #, tetapi di Lisp ini adalah gaya pengembangan default.

Jika Anda mengembangkan perangkat lunak yang kompleks menggunakan proses pengembangan interaktif atau perangkat lunak Anda memiliki bagian simbolis yang substansial (pemrograman meta, paradigma lain, aljabar komputer, komposisi musik, perencanaan, ...), maka Lisp mungkin tepat untuk Anda.

Jika Anda bekerja di lingkungan Windows (saya tidak), maka C # memiliki keuntungan, karena itu adalah bahasa pengembangan utama Microsoft. Microsoft tidak mendukung Lisp dalam bentuk apa pun.

Anda menulis:

  • Ruang nama. Bahkan dengan metode statis, saya suka mengikat mereka ke "kelas" untuk mengkategorikan konteksnya (tampaknya Clojure memiliki ini, CL sepertinya tidak.)

Lisp umum tidak melampirkan ruang nama ke kelas. Ruang nama disediakan oleh paket simbol dan tidak tergantung pada kelas. Anda perlu mengarahkan kembali pendekatan Anda ke pemrograman berorientasi objek jika Anda menggunakan CLOS.

  • Kompilasi yang hebat dan dukungan desain waktu sistem tipe memungkinkan saya untuk menentukan "kebenaran" dari struktur data yang saya lewati apa pun yang salah eja digarisbawahi secara realtime; Saya tidak harus menunggu sampai runtime untuk mengetahui peningkatan kode (seperti menggunakan pendekatan FP bukan yang imperatif) disarankan secara otomatis

Gunakan kompiler Lisp. Ini memberi tahu Anda tentang variabel tidak dikenal, mungkin memiliki rekomendasi gaya (tergantung pada kompiler yang digunakan), memberikan petunjuk efisiensi, ... Kompiler adalah keystroke jauh.

  • Alat pengembangan GUI: WinForms dan WPF (saya tahu Clojure memiliki akses ke perpustakaan GUI Java, tetapi semuanya sepenuhnya asing bagi saya.)

Lisps komersial seperti LispWorks dan Allegro CL menawarkan hal serupa di bawah Windows.

  • Alat Debugging GUI: breakpoints, step-in, step-over, pemeriksa nilai (teks, xml, custom), jam tangan, debug-by-thread, breakpoint bersyarat, jendela panggilan-tumpukan dengan kemampuan untuk melompat ke kode di tingkat mana pun di stack (Agar adil, tugas saya dengan Emacs + Slime tampaknya memberikan sebagian dari ini, tapi saya sebagian dengan pendekatan yang digerakkan VS GUI)

Lisps komersial seperti LispWorks dan Allegro CL menawarkan semua itu di bawah Windows.

Rainer Joswig
sumber
1
Kritik saya sebenarnya bukan tentang Lisps. Saya menemukan mereka cukup mampu. Saya mencari apa yang bisa dilakukan Lisp / memberi-saya yang belum saya lakukan. Saya sepenuhnya memahami bahwa sebagian besar C # devs tidak menggunakan banyak fitur bahasa "baru". Saya pikir poin yang lebih besar adalah yang saya lakukan, dan jujur, di luar GUI, saya hampir menulis dalam gaya FP 100%. FP adalah lompatan konseptual, tetapi layak dilakukan. Namun, beralih ke Lisp dari tempat saya tampaknya memberikan sedikit manfaat. Saya berharap menemukan bahwa ada alasan saya harus terus memberikan kesempatan.
@ Jonathan Mitchem: C # tidak benar-benar terlihat seperti bahasa FP, bahkan jika bahasa tersebut memiliki beberapa fitur yang mendukungnya dan beberapa perpustakaan mungkin menggunakannya. Jika Anda ingin melakukan pemrograman FP di eco-system Microsoft, maka F # mungkin cocok untuk Anda.
@Rainer Tidak, ini tidak terlihat seperti bahasa FP, tetapi bisa melakukannya, dan cukup kompak. Dan ketika saya ingin / butuh kode imperatif, atau OO, saya bisa melakukannya juga. (sedikit di luar topik: Saya tidak benar-benar menganggap F # bahasa serius yang layak untuk digali, saya lebih suka mengarahkan kepala saya ke sekitar monad di Haskell. Tetapi ketika saya adalah seorang C ++ dev dan C # keluar, saya tidak menganggapnya bahasa "nyata" baik [dan saat itu tidak, imho])
@ Jonathan Mitchem: mengapa saya harus mencari? Saya menulis bahwa C # mendukung beberapa fitur FP. Itu hanya ditambahkan ke bahasa berorientasi objek imperatif dan tidak membuatnya idiomatik, seperti dalam, katakanlah, Lisp, Skema dan terutama tidak dibandingkan dengan SML, F #, Haskell atau bahasa fungsional utama lainnya. Maksud saya adalah: beberapa FP dimungkinkan dalam C #, tetapi itu bukan fitur inti.
5

Rainier Joswig mengatakan itu yang terbaik.

Bagi saya, kekuatan Lisp tidak dapat dipahami hanya dengan melihat daftar fitur Lisp. Untuk Lisp, dan Common Lisp pada khususnya, keseluruhan lebih besar dari jumlah bagian. Bukan hanya REPL plus s-expressions plus macro plus multi-method dispatch plus closures plus paket plus CLOS plus restart plus X, Y dan Z. Ini seluruh shebang yang semuanya terintegrasi dengan cerdas. Ini adalah pengalaman sehari-hari yang sangat sangat berbeda dari pengalaman sehari-hari dari bahasa pemrograman lain.

Lisp terlihat berbeda, digunakan secara berbeda, seseorang mendekati pemrograman dengan cara yang berbeda saat menggunakannya. Elegan, lengkap, besar dan mulus. Ini bukan tanpa cacat dan peccadillo sendiri. Tentu saja ada perbandingan dengan bahasa lain yang mungkin dibuat di mana itu mungkin tidak keluar di depan. Tapi sama sekali tidak Lisp hanya bahasa X ditambah REPL dan makro, atau bahasa Y ditambah pengiriman multi-metode dan restart.


sumber
3
Code is Data (and Macros) - Mungkin saya belum "mendapatkan" makro, tapi saya belum melihat satu contoh pun di mana gagasan makro tidak dapat diimplementasikan sebagai fungsi; itu tidak mengubah "bahasa", tapi saya tidak yakin itu kekuatan

Biasanya, makro harus digunakan untuk sesuatu yang tidak dapat diungkapkan sebagai pemanggilan fungsi. Saya tidak tahu apakah ada conditional like switch di C # (mirip dengan yang ada di C, seperti switch (form) {case ...}), tetapi mari kita asumsikan demikian dan telah dekat dengan batasan yang sama ( membutuhkan tipe integral).

Sekarang, mari kita anggap lebih jauh bahwa Anda ingin sesuatu yang terlihat seperti itu, tetapi mengirimkan string. Dalam lisp (well, khususnya di Common Lisp dan mungkin di orang lain), itu adalah "hanya" makro dan jika Anda membatasi pengguna untuk memiliki string konstan (mungkin tidak sulit) untuk dicocokkan, Anda dapat (waktu kompilasi) menghitung urutan minimal tes untuk menentukan kasus apa yang cocok (atau menggunakan tabel hash, menyimpan penutupan, mungkin).

Meskipun dimungkinkan untuk menyatakan bahwa sebagai fungsi (perbandingan string, daftar kasus dan penutupan untuk dieksekusi), itu mungkin tidak akan terlihat seperti "kode normal" dan di situlah makro lisp memiliki kemenangan yang pasti. Anda mungkin telah menggunakan beberapa macro atau bentuk khusus taht yang makro-seperti, seperti defun, defmacro, setf, cond, loopdan banyak lagi.

Vatine
sumber
2

Ini adalah artikel penjelasan terbaik yang saya temukan yang membawa pembaca dari permukaan advokasi Lisp untuk menunjukkan beberapa implikasi yang lebih dalam dari konsep yang digunakan:

http://www.defmacro.org/ramblings/lisp.html

Saya ingat pernah membaca ide di tempat lain: Bahasa lain telah mengadopsi berbagai fitur Lisp; pengumpulan sampah, pengetikan dinamis, fungsi anonim, penutupan untuk menghasilkan C ++ / C / Algol yang lebih baik. Namun untuk mendapatkan kekuatan penuh Lisp Anda memerlukan semua fitur penting, di mana Anda memiliki dialek lain Lisp, keluarga bahasa yang berbeda yang telah ada dalam satu bentuk atau lainnya selama lebih dari 50 tahun.

spacebat
sumber