1 poin oleh GN⁺ 2024-10-18 | 1 komentar | Bagikan ke WhatsApp
  • Tulisan Douglas Hofstadter tahun 1983 memperkenalkan Lisp, yang banyak digunakan dalam riset AI, sebagai bahasa yang elegan dan fleksibel yang dibangun di atas kernel matematis kecil
  • Interaktivitas Lisp tampak dalam read-eval-print loop: ketika pengguna memasukkan ekspresi, interpreter membacanya, mengevaluasinya, mencetak hasilnya, lalu menunggu input berikutnya
  • Objek Lisp tersusun terutama dari atom dan list, sementara nil memiliki posisi khusus sebagai list kosong sekaligus atom
  • quote, eval, car, cdr, cons, setq, set, lambda, def, cond memungkinkan kode dan data diperlakukan sebagai struktur list yang sama, sehingga fungsi baru dapat dibuat secara bertahap
  • Komposisi fungsi, ekspresi kondisional, efek samping dan gaya applicative, serta pemikiran rekursif dirangkai lewat contoh; fungsi power di bagian akhir dan analogi “porpuquine” mengisyaratkan rekursi ala Lisp

Riset AI dan posisi Lisp

  • AI pada tahun 1983 adalah bidang riset yang berupaya mengimplementasikan perilaku seperti fleksibilitas, akal sehat, wawasan, kreativitas, kesadaran diri, dan humor pada komputer
  • Di Amerika Serikat ada sekitar 2.000 orang yang terlibat secara profesional dalam AI, dan di luar negeri ada peneliti dalam jumlah yang kurang lebih serupa
  • Para peneliti AI sangat terpecah soal jalur terbaik menuju AI, tetapi dalam pilihan bahasa pemrograman mereka hampir secara umum memakai Lisp
  • Nama Lisp berasal dari “list processing”, dan bukan akronim penuh
  • Daya tarik Lisp terletak pada sifatnya sebagai bahasa yang “crisp” dan “elegant”
    • Sementara banyak bahasa memuat banyak fitur arbitrer, beberapa bahasa seperti Lisp dan Algol tersusun di sekitar kernel yang terasa alami, seperti cabang matematika
    • Kernel Lisp memiliki “crystalline purity”, dan kemurnian ini berkontribusi bukan hanya pada rasa estetis tetapi juga pada fleksibilitas

Dari logika matematika ke bahasa pemrosesan list

  • Akar mendalam Lisp berada dalam logika matematika
    • Gagasan yang ditinggalkan Thoralf Skolem, Kurt Godel, dan Alonzo Church dalam logika pada 1920–1930-an kelak masuk ke dalam Lisp
  • Pemrograman komputer yang sesungguhnya dimulai pada 1940-an, dan bahasa tingkat tinggi seperti Lisp muncul pada 1950-an
  • Bahasa pemrosesan list pertama bukan Lisp, melainkan IPL(Information Processing Language)
    • IPL dikembangkan pada pertengahan 1950-an oleh Herbert Simon, Allen Newell, dan J. C. Shaw
  • John McCarthy menciptakan bahasa pemrosesan list aljabar bernama Lisp pada 1956–1958 berdasarkan gagasan-gagasan yang sudah ada
    • Lisp dengan cepat menyebar di kalangan peneliti muda di sekitar MIT Artificial Intelligence Project
    • Bahasa ini diimplementasikan pada IBM 704 dan menyebar ke kelompok-kelompok AI lain
    • Berbagai dialek muncul, tetapi semuanya berbagi kernel pusat yang elegan

Lisp yang interaktif dan REPL

  • Berbeda dari banyak bahasa tingkat tinggi lain, Lisp disajikan sebagai bahasa interaktif
  • Pengguna menjalankan Lisp di terminal, melihat prompt, lalu memasukkan ekspresi
    • Contoh: jika memasukkan (plus 2 2), 4 dicetak dan prompt baru muncul
  • Operasi inti interpreter Lisp adalah read-eval-print loop
    • Membaca ekspresi
    • Mengevaluasi ekspresi
    • Mencetak nilai yang sesuai
    • Memberi tahu bahwa ia siap membaca ekspresi berikutnya
  • Berkat struktur ini, pengguna dapat memasukkan “keinginan” satu per satu dan langsung memeriksa hasilnya
  • Dalam banyak bahasa non-interaktif, seluruh program harus ditulis dan dijalankan terlebih dahulu, sehingga banyak tahap harus saling pas dengan sempurna, dan perbaikan kesalahan pun tidak langsung serta mahal
  • Lisp memungkinkan pengembangan dan debugging bertahap dengan menjalankan ekspresi satu demi satu

Notasi Polish dan tanda kurung

  • Ekspresi aritmetika Lisp memakai notasi Polish, dengan operator diletakkan sebelum operand
    • Contoh: (times (plus 6 3) (difference 6 3)) dievaluasi menjadi 27
  • Notasi ini dibuat sebelum era komputer oleh logikawan Polandia Jan Lukasiewicz
  • Ekspresi Lisp banyak mengandung tanda kurung
    • Ekspresi panjang sering berakhir dengan beberapa tanda kurung penutup
    • Awalnya terasa membebani, tetapi setelah terbiasa, struktur logikanya terlihat intuitif
  • Contoh-contoh disajikan dalam bentuk pretty printing yang menampilkan struktur lewat indentasi

Atom, list, nil

  • Inti Lisp adalah struktur yang dapat dimanipulasi, dan semua program bekerja dengan membuat, mengubah, dan menghancurkan struktur
  • Struktur ada dua jenis
    • Atom: objek dasar yang tidak dapat dibagi lagi
    • List: struktur berisi beberapa elemen dalam urutan tertentu
  • Semua objek Lisp adalah atom atau list, dengan satu pengecualian yaitu nil
    • nil adalah atom sekaligus list
    • nil merepresentasikan list kosong
    • () dan nil bermakna sama, tetapi nil lebih sering digunakan
  • Elemen list bisa berupa atom maupun list
    • Contoh: (zonk blee strill (croak flonk)) adalah list berisi empat elemen, dan elemen terakhirnya adalah list lain berisi dua elemen
  • Kalimat Lisp sendiri juga berupa list
    • (plus 2 2) juga sebuah list
    • Interpreter Lisp dapat memanipulasi list dan atom untuk membuat dan mengevaluasi “perintah” baru

Nilai, quote, eval

  • Atom dapat memiliki nilai
    • Atom angka memiliki dirinya sendiri sebagai nilai permanen
    • Nilai nil adalah nil
    • t juga atom khusus yang memiliki dirinya sendiri sebagai nilai permanen
  • setq menetapkan nilai pada atom
    • (setq pie 4) membuat nilai pie menjadi 4
    • (setq pie (plus 2 2)) juga membuat nilai pie menjadi 4
  • Nilai atom tidak hanya bisa berupa angka, tetapi juga objek Lisp apa pun
    • Bisa atom, bisa juga list
  • quote mencegah evaluasi dan membuat list atau atom diperlakukan apa adanya sebagai data
    • (setq pie (plus 2 2)) mengevaluasi ekspresi di dalamnya dan menyimpan 4 ke pie
    • (setq pi '(plus 2 2)) menyimpan list (plus 2 2) itu sendiri ke pi
  • eval mengevaluasi kembali ekspresi yang tersimpan sebagai nilai
    • Jika nilai pi adalah (plus 2 2), maka (eval pi) mengembalikan 4
    • Interpreter biasanya hanya mengevaluasi satu tingkat, tetapi dengan eval kita dapat meminta evaluasi tambahan

car, cdr, cons

  • Semua list yang bukan nil memiliki setidaknya satu elemen, dan elemen pertamanya disebut car
    • car dari (eval pi) adalah eval
    • car dari (plus 2 2) adalah plus
  • car tidak harus berupa nama fungsi
    • car dari ((1)(2 2) (3 3 3)) adalah (1)
  • List yang tersisa setelah car dihapus disebut cdr
    • cdr dari (a b c d) adalah (b c d)
    • Lalu menyusut menjadi (c d), (d), dan nil
  • Nil tidak memiliki car maupun cdr, dan mengambil car atau cdr darinya semestinya menghasilkan error
  • cons membuat list baru dengan menempelkan car baru di depan list yang sudah ada
    • Ketika x adalah (cake cookie), (cons 'pie x) membuat (pie cake cookie)
    • Dalam proses ini, x yang lama tidak berubah
  • Hasilnya berbeda tergantung ada tidaknya quote
    • Jika nilai pie adalah 4, (cons pie x) mengembalikan (4 cake cookie)
    • (cons 'pie x) menempelkan nama atom pie itu sendiri di depan

Perbedaan setq dan set

  • Interpreter Lisp tidak selalu mengevaluasi argumen, dan setq adalah pengecualian yang representatif
  • Argumen pertama setq tidak dievaluasi dan diperlakukan apa adanya sebagai nama variabel
    • Huruf q pada setq berarti quote, sehingga argumen pertama diperlakukan seolah-olah dikutip
  • set mirip dengan setq, tetapi argumen pertamanya juga dievaluasi
    • Ketika nilai x adalah k, (set x 7) tidak mengubah x, melainkan mengubah nilai k menjadi 7
  • Urutan berikut disajikan sebagai contoh
    • (setq a 'b)
    • (setq b 'c)
    • (setq c 'a)
    • (set a c)
    • (set c b)
  • Setelah eksekusi ini, nilai a, b, dan c masing-masing semuanya menjadi a
  • set jarang digunakan, dan kebingungan semacam ini juga tidak sering terjadi

Definisi fungsi dan lambda

  • Kekuatan besar pemrograman terletak pada kemampuan mendefinisikan operasi majemuk baru dari operasi yang sudah ada, lalu mengulanginya untuk membangun repertoar operasi yang lebih kompleks
  • Dalam Lisp, fungsi baru didefinisikan dari fungsi-fungsi yang sudah diketahui
  • rac adalah contoh fungsi yang mengembalikan elemen terakhir dari sebuah list
    • Untuk mendapatkan elemen terakhir, balik list lalu ambil car-nya
    • Definisi: (def rac (lambda (lyst) (car (reverse lyst))))
  • (lyst) setelah lambda menunjukkan parameter fungsi, yaitu variabel dummy
  • Setelah didefinisikan dengan def, rac menjadi fungsi yang dapat digunakan seperti car
    • (rac '(your brains)) mengembalikan brains
  • Fungsi readers-digest-condensed-version membuat list pendek yang hanya berisi elemen pertama dan terakhir dari sebuah list panjang
    • Jika seluruh Finnegans Wake karya James Joyce diperlakukan sebagai list kata, muncul contoh yang menghasilkan (riverrun the)
  • Operasi kebalikan bernama rejoyce adalah fungsi imajiner yang menghasilkan novel dengan awal dan akhir yang ditentukan oleh dua kata, dan penulisannya ditinggalkan sebagai latihan bagi pembaca

Nilai balik, efek samping, gaya applicative

  • Sebagian orang memandang dua tujuan berikut sebagai hal yang diinginkan dan mungkin dalam Lisp serta bahasa terkait
    • Semua kalimat mengembalikan nilai
    • Efek sebuah kalimat terjadi hanya melalui nilai baliknya
  • Dialek Lisp yang dibahas dalam tulisan ini memenuhi syarat pertama, tetapi tidak selalu memenuhi syarat kedua
  • (reverse x) tidak mengubah x itu sendiri, melainkan membuat dan mengembalikan list baru yang sama dengan x tetapi urutannya dibalik
    • Ini sama seperti (plus 2 2) tidak mengubah nilai 2
  • cons juga mengembalikan list baru tanpa mengubah list yang sudah ada
  • Sebaliknya, setq adalah contoh perintah yang meninggalkan efek samping dengan mengubah binding variabel
    • Selain perubahan binding variabel, efek samping juga dapat mencakup input/output
  • Pendukung pemrograman applicative lebih menyukai cara fungsi menghitung dan meneruskan nilai tanpa efek samping
  • Dalam gaya ini, binding yang diperbolehkan adalah lambda binding yang muncul sementara selama pemanggilan fungsi
    • Setelah perhitungan fungsi selesai, binding variabel dummy menghilang
  • Narator tulisan ini memandang gaya applicative sebagai sesuatu yang elegan, tetapi tidak praktis untuk membuat program besar bergaya AI
  • Dalam pemrograman applicative yang ketat, def pun menjadi kasus ekstrem yang tidak diperbolehkan karena menyimpan definisi fungsi permanen di memori

Ekspresi kondisional cond dan keputusan

  • Agar Lisp dapat melakukan hal yang lebih menarik, ia harus mampu mengambil keputusan berdasarkan apa yang terjadi di tengah proses, dan untuk itu diperlukan ekspresi kondisional
  • Contoh: (cond ((eq x 1) 'land) ((eq x 2) 'sea))
    • Jika x adalah 1, hasilnya land
    • Jika x adalah 2, hasilnya sea
    • Selain itu, mengembalikan nil
  • eq adalah fungsi Lisp yang mengembalikan t jika nilai kedua argumennya sama, dan nil jika berbeda
  • Pernyataan cond dimulai dengan nama fungsi cond dan memiliki beberapa klausa
    • Setiap klausa adalah list 2 elemen yang terdiri dari kondisi dan hasil
    • Kondisi diperiksa berurutan; ketika ditemukan kondisi pertama yang mengembalikan nilai bukan nil, hasil yang sesuai dievaluasi dan dikembalikan sebagai nilai seluruh cond
    • Klausa berikutnya tidak diperiksa
  • Jika klausa catch-all dengan kondisi t diletakkan di akhir, hasil default dapat dikembalikan alih-alih nil
    • Contoh yang disajikan adalah cond yang mengembalikan air jika kondisi land dan sea sama-sama gagal

Pangkat dan struktur rekursif

  • Di bagian akhir tulisan muncul definisi fungsi dengan pola yang jelas
    • square adalah k * k
    • cube adalah k * square(k)
    • 4th-power adalah k * cube(k)
    • Dan seterusnya dengan cara yang sama
  • Pertanyaan yang diajukan adalah apakah fungsi dua parameter power yang mencakup seluruh pola ini sekaligus dapat didefinisikan
    • (power 9 3) adalah 729
    • (power 7 4) harus mengembalikan 2.401
  • Semua alat yang diperlukan telah disajikan dalam teks, dan ini menuntut kecerdikan pembaca
  • Kisah Glazunkian porpuquine di bagian akhir memperlakukan struktur rekursif seperti sebuah fabel
    • Duri porpuquine adalah porpuquine yang lebih kecil
    • Di Outer Glazunkia selalu ada 9 duri, sedangkan di Inner Glazunkia selalu ada 7 duri
    • Porpuquine berukuran 0 inci tidak memiliki duri, sehingga menghentikan regresi tak berhingga
  • “buying power” atau “power” hewan ini dikaitkan dengan jumlah hidung porpuquine kecil berukuran 0 inci yang terkandung di dalamnya, dan tulisan ditutup dengan analogi yang tersambung ke masalah power sebelumnya

Konteks pemuatan ulang teks asli

  • Bagian awal Gist menjelaskan bahwa tulisan ini adalah pengantar Lisp oleh Douglas Hofstadter yang ditemui dalam edisi lama Scientific American dari pertengahan 1980-an
  • Contoh-contohnya masih dapat dijalankan di Emacs jika memasang beberapa alias
    • plus+
    • quotient/
    • times*
    • difference-
  • Bagian akhir menyarankan bahwa jika pembaca menikmati panduan Lisp khas Hofstadter ini, mereka dapat melihat tulisan serupa lainnya dalam bukunya Metamagical Themas

1 komentar

 
GN⁺ 2024-10-18
Komentar Hacker News
  • Nama fungsi "oval" dan "snot" di contoh sempat membingungkan, lalu beberapa detik kemudian saya sadar bahwa keduanya adalah salah ketik dari "eval" dan "snoc"
    Kode aslinya seharusnya dibaca seperti (cond ((eq (eval pi) pie) (eval (snoc pie pi))) (t (eval (snoc (rac pi) pi))))
    Setelah mengunduh dan memeriksa artikel Scientific American aslinya dari https://www.jstor.org/stable/24968822, ternyata oval/snot memang salah ketik dari eval/snoc

    • Koreksi atas koreksi: "oval" dan "snot" memang salah ketik dari "eval" dan "snoc"
      Dan snoc tampaknya adalah cons yang dibalik, sedangkan rac adalah car yang dibalik
    • Bisa jadi ini kesalahan OCR
  • Tulisan ini kembali menunjukkan bahwa salah satu penyebab utama Lisp kurang populer adalah cara Lisp dijelaskan
    Tulisan-tulisan tentang Lisp seperti ini sama sekali tidak memberi tahu saya semasa kecil hal-hal yang benar-benar bisa dipakai, juga tidak menunjukkan seberapa jauh pekerjaan X menjadi lebih mudah dibanding assembly/C/Pascal
    Kalau saya yang menulis sekarang, saya akan menunjukkan, “Pemeriksa ejaan yang butuh 7 bulan dalam assembly? Di Lisp pada mikrokomputer dengan memori bank-switched itu nyaris sepele, dan garbage collection pun bisa dibuat menentukan bahkan pada CPU yang buruk”
    Begitu banyak tulisan dan buku ajar Lisp hanya mengulang soal list, rekursi, dan AI tanpa menunjukkan cara melakukan hal yang berguna, sampai terasa seperti membuang waktu memrogram dengan pinset, butir beras, dan lem

    • Common Lisp: A Gentle Introduction to Symbolic Computation mungkin berguna dalam konteks ini: https://www.cs.cmu.edu/~dst/LispBook/
    • Ada juga Practical Common Lisp: https://gigamonkeys.com/book/
    • Tulisan lanjutan Hofstadter punya contoh yang lebih menarik
      Di majalah Byte yang pertama kali saya lihat saat kecil, ada kode Lisp untuk diferensiasi simbolik dan penyederhanaan aljabar; meski sulit diikuti, tetap terasa ada sesuatu yang memikat
      Rasanya itu tidak mungkin lebih mudah dalam Basic, dan belakangan saya sadar kodenya juga bukan contoh yang sangat bagus, tetapi saya baru benar-benar jatuh hati pada Lisp setelah bertemu XLisp di PC akhir 80-an dan SICP
  • Saya sangat menyukai gaya menulis Hofstadter. Ia menangkap dengan baik perasaan saat menemukan Lisp
    Saya anak yang belajar pemrograman pada 80-an, dan di awal SMA serta kuliah saya sudah sedikit mencoba BASIC, Fortran, Pascal, dan COBOL; ada perbedaannya, tetapi pada dasarnya mereka punya kesamaan
    Lalu kelas ilmu komputer pertama di UC Berkeley diajarkan dengan Scheme, sebuah dialek Lisp, dan itu benar-benar mengejutkan
    Seperti kata Hofstadter, rasanya paling dekat dengan matematika, sangat mengingatkan pada banyak kelas teori matematika, dan itu adalah bahasa pertama yang saya anggap indah
    Saya sangat menyukai kutipan, “Lisp dan Algol dibangun di sekitar inti alami yang menyerupai cabang matematika. Di inti Lisp ada kemurnian kristalin yang bukan hanya menarik secara estetis, tetapi juga membuatnya jauh lebih fleksibel daripada kebanyakan bahasa”

    • Penasaran apakah Anda pernah memakai Haskell. Bagi saya, itu terasa jauh lebih dekat ke matematika karena tersusun dari definisi, bukan prosedur, dan tampilannya pun seperti matematika
    • Meski ada risiko agak menyimpang dari tulisan aslinya, menurut saya menyebut ini sebagai “matematika” justru bisa mengaburkannya
      Bahkan dari sudut pandang seseorang yang ingin menjadi ahli topologi aljabar, Scheme lebih mirip ekspresi yang elegan dan minimal dari gaya pemrograman yang menyebar ke bahasa-bahasa bertipe dinamis dengan garbage collection
      Ia terasa seperti “teori” dalam arti tampak lengkap, dan jika seseorang memikirkan cara menyelesaikan masalah di Scheme lalu memindahkannya ke bahasa dinamis lain, orang itu masih bisa mencapai solusi yang elegan
      Scheme adalah bahasa yang menyederhanakan dan merapikan Lisp tradisional saat itu, misalnya lewat lexical scope dan satu namespace untuk fungsi serta variabel
  • Pada tahun 1983, bidang ini sudah berjalan sekitar 20 tahun, tetapi masih membicarakan AI yang memrogram komputer agar punya “fleksibilitas, akal sehat, wawasan, kreativitas, kesadaran diri, humor”
    Daftar ini cukup lucu karena terbaca seperti daftar hal-hal yang benar-benar buruk dilakukan LLM
    Meski begitu, setidaknya sekarang sudah ada kemajuan yang tidak nol ke arah itu

    • Dibandingkan orang biasa yang saya temui, LLM tampaknya sudah menunjukkan akal sehat, wawasan, kreativitas, kesadaran diri, humor setidaknya setara manusia rata-rata
      Mungkin bahkan lebih, tetapi kalau saya mengatakannya begitu, rasanya agak aneh bahkan bagi saya sendiri
    • Kelompok riset Hofstadter punya sejarah panjang dalam mencoba menangani masalah-masalah ini
      Meski banyak hal masih belum membuahkan hasil, tetap menarik untuk dibaca
  • Dua tulisan pendamping yang disebut bersama artikel ini dimuat sebagai bab 17~19 dalam buku Hofstadter Metamagical Themas, bersama artikel lain dari seri yang sama di Scientific American
    [0]: https://www.goodreads.com/book/show/181239.Metamagical_Thema...
    Judul bukunya berasal dari judul seri yang merupakan anagram dari “Mathematical Games”, kolom yang ditulis Martin Gardner di Scientific American, lalu dilanjutkan oleh Hofstadter

    • Saya sangat menyukai buku ini. Sangat direkomendasikan bagi siapa pun yang menyukai karya klasik Hofstadter Gödel, Escher, Bach
    • Buku ini sangat indah untuk dibaca maupun dilihat, dan penuh ilustrasi menarik
  • Tulisan itu mengatakan bahwa menerapkan car atau cdr pada nil seharusnya menghasilkan error seperti membagi dengan nol, tetapi di Lisp modern sering kali sudah tidak demikian lagi
    Dalam Lisp asli yang didefinisikan John McCarthy, CAR dan CDR memang tidak didefinisikan untuk NIL: <https://dl.acm.org/doi/pdf/10.1145/367177.367199>
    Namun Common Lisp dan Emacs Lisp mendefinisikan (car nil) dan (cdr nil) sebagai nil: <https://www.lispworks.com/documentation/HyperSpec/Body/f_car...>, <https://www.gnu.org/software/emacs/manual/html_node/elisp/Li...>

    • Karena penasaran bagaimana perilakunya di Maclisp, saya masuk ke ITS publik milik Lars Brinkhoff lewat telnet untuk memeriksanya
      Di LISP 2156, (status lispversion) mengembalikan /2156, dan (car nil) serta (cdr nil) sama-sama mengembalikan NIL
    • Menarik bahwa pada kelahiran sebuah bahasa yang dirancang secara matematis, detail implementasi yang sangat spesifik seperti car dan cdr justru menjadi bagian inti
      Operasi paling dasar dan paling terkenal dari “List Processor” ternyata tidak dibuat untuk bekerja pada list, melainkan pada cons, elemen representasi mesin tertentu yang dipakai Lisp saat membangun struktur data
      cons juga tidak selalu ditafsirkan sebagai list, dan list yang sangat penting sebagai kasus dasar fungsi rekursif pada list bahkan tidak direpresentasikan sebagai cons
      Bahkan setelah 60 tahun, sebagian besar program Lisp masih dipenuhi operasi cons, dan mungkin nama yang lebih tepat adalah “Cons Processor”
      Ini mengingatkan bahwa Lisp lahir pada masa ketika bahasa dan implementasi harus saling terkait erat, sehingga pencapaian membangun bahasa komputer di atas logika matematika terasa makin mengagumkan
    • Scheme tidak demikian. Mengambil CAR atau CDR dari nil akan menghasilkan error
    • Sayangnya, di Scheme, car/cdr pada nil adalah error, jadi bagi pemula seperti saya, kodenya terasa cukup tidak ergonomis
      Meski begitu, saya tetap lebih menyukai Guile Scheme dibanding Common Lisp, jadi agak disayangkan
    • Saya penasaran apakah ada istilah untuk pilihan desain bahasa yang memungkinkan penerapan sesuatu pada nil tanpa error lalu mengembalikan nil lagi
      SQL juga terlintas, dan secara pribadi saya menganggap itu pilihan yang kurang baik, jadi kalau belum ada istilah lain saya ingin menyebutnya “bleeding nils/NULLs”
      Terutama jika nil tidak sama dengan false dalam perbandingan boolean, itu terasa lebih buruk lagi
      Di Ruby dan Elixir, nil diperlakukan seperti false, dan Elixir membedakan and yang hanya menerima boolean murni dengan && yang memperlakukan nil sebagai false
      Desain seperti ini awalnya memang bisa membuat kode tampak rapi, tetapi nil yang sebenarnya merupakan error penanganan bisa baru muncul di bagian yang sama sekali berbeda setelah beberapa lapis call stack, sehingga debugging jauh lebih sulit
  • Saya sudah tahu informasi Lisp dalam tulisan ini, tetapi tetap membacanya dengan senang. Gaya bahasa Hofstadter memang sangat memikat
    Terutama leluconnya saat ia membuat rejoyce, operasi kebalikan dari readers-digest-condensed-version, sehingga jika menjalankan (rejoyce 'Stately 'Yes), peri Lisp akan menghasilkan seluruh Ulysses seperti yang kira-kira akan ditulis James Joyce, dari awal
    Memang butuh waktu, tetapi kita akhirnya sampai juga ke titik itu, dan meskipun AI tahun 2024 tidak persis sama dengan yang ia bayangkan pada 1983, mereproduksi teks dari seed pendek adalah jenis tugas yang sangat cocok untuk AI saat ini

  • Lisp masih dianggap sebagai bahasa utama yang mampu menampung konsep strange loop yang dibahas Hofstadter
    Lisp memang bukan satu-satunya bahasa yang homoikonik, tetapi di antara bahasa yang benar-benar bisa dipakai orang, Lisp termasuk yang terbesar yang eval-nya tidak menerima string yang harus diparse
    Saya tidak suka ketika orang menyamakan Lisp dengan pemrograman fungsional secara keseluruhan
    Bukannya saya membenci pemrograman fungsional, tetapi sifat simbolik Lisp jauh lebih menarik, dan selalu terasa menyenangkan bahwa bahasa ini juga sangat mudah dipakai untuk membuat kode yang digerakkan oleh bagian (go tag), sehingga pemrograman bergaya GOTO pun sangat mudah dilakukan

    • Ada juga bahasa homoikonik lain yang benar-benar fungsional, yaitu XSLT, yang sempat menikmati adopsi arus utama sebentar pada era 2000-an
      Dengan XSLT dan XML, metaprogramming yang menghasilkan XSLT alih-alih menulis langsung kode berulang cukup banyak digunakan
      Hanya saja, sintaksnya merupakan masalah yang bahkan lebih besar daripada sintaks Lisp
      Tidak mudah membuat bahasa yang sintaksnya enak dipakai sehari-hari sekaligus tidak terlalu berat untuk diperlakukan sebagai abstract syntax tree, dan Lisp adalah salah satu dari sedikit contoh yang relatif berhasil
    • Terutama ketika masuk ke pemrograman berbasis continuations di Scheme, batas antara pemrograman fungsional dan nonfungsional menjadi kabur sampai hampir tidak lagi bermakna
    • Saya penasaran apa sebenarnya bentuk dukungan homoikonik/simbolik tingkat mendalam yang didapat programmer tahun 2024 dari Lisp, yang tidak benar-benar bisa dicapai dengan functools di Python: https://docs.python.org/3/library/functools.html
      Saya sedang membangun AGI simbolik tanpa Lisp, dan ingin mendengar petunjuk dari para ahli
      Sejauh yang saya pahami, fitur di Python itu mencakup fungsi seperti filter(), map(), reduce() yang menerapkan fungsi lain ke iterable, wrapper seperti @singledispatch yang merutekan pemanggilan, fungsi seperti @cache dan partial() yang memberi kemudahan untuk kontrol alur atau performa, serta kemampuan membungkus fungsi secara arbitrer seperti wraps()
      Sebagian besar hal ini tampak seperti fitur kenyamanan untuk memanggil fungsi dengan cara yang tidak biasa, dan rasanya belum sampai ke tingkat pujian terhadap Lisp yang memperlakukan “introspeksi diri” sebagai perhatian kelas satu
      Saya ingin tahu apa sebenarnya yang Lisp sediakan yang tidak ada pada fitur-fitur di atas
    • Ini juga karena banyak orang hanya mengenal Lisp lewat akademia, dan para akademisi yang mengajarkan Lisp tidak terlalu tertarik mengembangkan sesuatu yang nyata dengan Lisp
      Mereka memakai Lisp sebagai sarana menyampaikan konsep, dan konsep itu biasanya berputar di sekitar rekursi fungsional
      Scheme dan budaya di sekitarnya juga berperan
      Scheme memang bukan semata-mata bahasa fungsional, tetapi dibandingkan keluarga Lisp sebelumnya ia lebih menekankan pemrograman murni, bahasa dasarnya menyediakan struktur tail recursion alih-alih struktur iterasi, dan menuntut implementasinya melakukan optimisasi tail call
  • Bahkan di Common Lisp, defalias bisa didefinisikan sebagai makro dan dipakai seperti defalias di Emacs: https://stackoverflow.com/questions/24252539/defining-aliase...

  • Saya menyukai tulisan Hofstadter tentang Lisp yang dimuat di Metamagical Themas, dan pernah memindahkan serta merapikan kode dari artikel penutup serial itu agar cocok untuk Clojure dalam kelompok belajar di tempat kerja
    [1] http://johnj.com/posts/oodles/

    • Saya juga penasaran apakah ada versi terjemahan yang dipindahkan ke Lisp modern