Artikel mendalam tentang teknologi yang membentuk masa depan.

Mengapa Lisp Masih Penting Setelah Enam Dekade

Lisp sudah berusia 65+ tahun tapi masih memengaruhi desain bahasa modern. Mengapa ia bertahan dan apa yang bisa dipelajari developer hari ini.

Pohon kuno dengan cabang yang terbentuk dari tanda kurung bersarang, berbuah bercahaya

Setiap beberapa tahun, seseorang menulis esai 'Lisp sudah mati', dan setiap beberapa tahun pula orang lain menunjukkan bahwa separuh fitur di bahasa modern favoritmu ternyata 'dicuri' dari Lisp. Garbage collection, first-class functions, closure, dynamic typing, homoiconicity, pengembangan berbasis REPL, macro — semuanya ditemukan atau dipopulerkan di Lisp jauh sebelum kebanyakan developer hari ini lahir. Lisp adalah jenis proyek yang butuh puluhan tahun untuk benar-benar dihargai.

Tapi ya begitulah. Tanyakan pada developer aktif apakah mereka pernah memakai Lisp, dan sebagian besar akan menjawab tidak. Tanyakan apakah mereka mau memulai proyek produksi dengan Lisp, dan mereka akan menatapmu aneh. Ada paradoks di sini: ide-ide Lisp menaklukkan dunia pemrograman, tapi Lisp sendiri tetap menjadi bahasa niche. Memahami alasannya jauh lebih menarik daripada argumen 'Lisp bagus, bahasa lain jelek' yang biasa muncul dalam kampanye pro-Lisp.

Apa yang Sebenarnya Benar dari Lisp

Lisp diciptakan oleh John McCarthy pada 1958. Untuk gambaran, FORTRAN baru berusia satu tahun saat itu. COBOL belum ada. Minikomputer PDP-1 baru akan dirilis dua tahun kemudian. Lisp dirancang di atas kertas dan diimplementasikan di IBM 704 — mesin yang memenuhi satu ruangan dan memakai word 36-bit.

Meski begitu, McCarthy membuat pilihan desain yang masih relevan enam dekade kemudian. Yang paling besar:

Kode sebagai Data (Homoiconicity)

Di sebagian besar bahasa, kode dan data pada dasarnya berbeda. Kamu menulis kode dalam sebuah sintaks, dan kode itu memanipulasi struktur data. Di Lisp, kode adalah data. Program Lisp tersusun dari list. Ekspresi (+ 1 2) sekaligus merupakan pemanggilan fungsi yang menjumlahkan 1 dan 2, dan juga sebuah list berisi tiga elemen: simbol +, angka 1, dan angka 2. Kamu bisa memanipulasi list itu — menyusunnya ulang, menambah elemen, mentransformasinya — lalu mengeksekusi hasilnya.

;; This is a function call
(+ 1 2)  ; => 3
;; This is a list containing the same elements
'(+ 1 2)  ; => (+ 1 2)
;; You can build code as data and then evaluate it
(def my-expr '(+ 1 2))
(eval my-expr)  ; => 3
;; Or transform it
(def doubled (list '* 2 my-expr))
;; doubled is now (* 2 (+ 1 2))
(eval doubled)  ; => 6

Ini terdengar seperti keunikan kecil sampai kamu sadar apa yang dimungkinkannya: program yang menulis program. Macro Lisp tidak melakukan substitusi teks seperti macro preprocessor C. Ia menerima struktur program yang sebenarnya sebagai struktur data, mentransformasinya menggunakan seluruh kekuatan bahasa, lalu mengembalikan struktur program yang baru. Ini adalah code generation saat kompilasi, dengan kompilatornya sendiri sebagai API-mu.

REPL sebagai Lingkungan Pengembangan

Lisp merintis Read-Eval-Print Loop — gagasan bahwa kamu seharusnya bisa mengetik sebuah ekspresi, langsung mengevaluasinya, dan melihat hasilnya. Ini terdengar biasa saja di era ketika setiap bahasa punya REPL, tapi REPL Lisp melangkah lebih jauh dari kebanyakan.

Di Common Lisp atau Clojure, kamu tidak sekadar menguji ekspresi terisolasi di REPL. Kamu mengembangkan seluruh sistem secara interaktif. Kamu mendefinisikan sebuah fungsi, mengujinya, mendefinisikannya ulang, semuanya saat program masih berjalan. Kamu bisa memeriksa dan mengubah state yang sedang berjalan. Kamu bisa mengompilasi ulang satu fungsi tanpa me-restart aplikasi. Siklus pengembangannya bukan write-compile-run-debug — melainkan percakapan berkelanjutan dengan sistem yang hidup.

Developer Clojure khususnya sering bekerja dengan cara ini: mereka menyambungkan editor ke REPL yang sedang berjalan, menulis kode di editor, mengevaluasi ekspresi satu per satu dengan satu tombol, dan langsung melihat hasilnya. Umpan balik diukur dalam milidetik, bukan menit. Setelah terbiasa bekerja seperti ini, siklus edit-compile-restart tradisional terasa seperti berkomunikasi lewat surat.

Sintaks Minimal, Fleksibilitas Maksimal

Sintaks Lisp — atau ketiadaannya — adalah fitur paling kontroversial. Tidak ada special form untuk statement if, loop for, atau definisi class. Semuanya adalah list dengan operator di depan: (if condition then-expr else-expr), (defn name [args] body), (for [x (range 10)] (* x x)). Tanda kurung yang membuat pemula merasa tidak nyaman adalah harga untuk bahasa dengan keteraturan sintaks paling konsisten yang pernah dirancang.

Keteraturan ini punya manfaat praktis: tooling. Ketika setiap konstruksi mengikuti pola (operator operands...) yang sama, editor bisa melakukan indentasi, refactor, dan navigasi kode secara struktural dengan andal. 'Pilih ekspresi pembungkus' tidak ambigu di Lisp — selalu berarti pasangan tanda kurung yang cocok. Di bahasa dengan sintaks yang beragam, structural editing masih menjadi masalah yang belum terpecahkan. Di Lisp, masalah itu sudah diselesaikan sejak 1960-an.

Mengapa Lisp Tidak Menang

Kalau Lisp memang sebagus itu, kenapa tidak semua orang memakainya? Jawaban standar dari para pendukung Lisp adalah 'industrinya yang salah', yang tidak membantu dan sebagian besar keliru. Lisp tidak meraih adopsi mainstream karena alasan-alasan nyata dan tidak sepele.

  • Kesenjangan ekosistem. Library lebih penting daripada fitur bahasa untuk sebagian besar pekerjaan praktis. Python tidak populer karena sintaksnya indah — ia populer karena pip install langsung memberi akses ke ribuan paket yang terawat baik untuk data science, pengembangan web, machine learning, dan hampir semua hal lain. Ekosistem Lisp (Common Lisp, Scheme, Clojure) memang solid, tapi jauh lebih kecil. Kamu akan lebih banyak menghabiskan waktu menulis ulang dari nol atau mengadaptasi library yang kurang terawat.
  • Kurva belajarnya berada di awal. Sintaks Lisp yang berbasis tanda kurung memang sangat sederhana setelah kamu memahaminya, tapi itu tetap penghalang nyata bagi pemula. Lebih penting lagi, menulis Lisp yang idiomatik menuntut cara berpikir yang asing bagi mereka yang datang dari bahasa prosedural atau berorientasi objek. Hasilnya datang belakangan, tapi banyak developer sudah menyerah sebelum sampai di sana.
  • Fragmentasi. 'Lisp' bukan satu bahasa — melainkan sebuah keluarga. Common Lisp, Scheme, Racket, Clojure, Emacs Lisp, Hy, Janet — masing-masing dengan kekuatan, ekosistem, dan komunitas yang berbeda. Fragmentasi ini mencegah konsentrasi usaha yang dibutuhkan agar ekosistem bisa tumbuh.
  • Dukungan korporasi itu penting. Java punya Sun. C# punya Microsoft. Go punya Google. Python punya Google dan komunitas data science yang besar. Bahasa keluarga Lisp paling sukses di produksi, Clojure, mendapat traksi sebagian karena Rich Hickey adalah pemikir dan komunikator yang sangat jernih — tapi tetap kekurangan dorongan institusional yang menggerakkan adopsi mainstream.

Clojure: Lisp yang Belajar dari Sejarah

Clojure layak mendapat perhatian khusus karena ia menunjukkan cara mengambil kekuatan Lisp dan membuatnya praktis untuk pengembangan perangkat lunak modern. Rich Hickey merancang Clojure pada 2007 dengan kesadaran eksplisit mengapa Lisp sebelumnya tidak meraih adopsi mainstream, dan ia membuat trade-off yang disengaja.

  • Berjalan di JVM. Alih-alih membangun ekosistem terpisah dari nol, Clojure berjalan di Java Virtual Machine dan bisa langsung memakai library Java apa pun. Butuh driver database? Pakai yang Java. Butuh HTTP client? Pakai yang Java. Keputusan tunggal ini memberi Clojure akses ke ribuan library yang sudah teruji sejak hari pertama.
  • Immutable secara default. Struktur data inti Clojure — list, vector, map, set — bersifat immutable. Kamu tidak memodifikasi map, melainkan membuat map baru dengan perubahanmu. Ini menghilangkan kategori bug konkurensi secara utuh dan membuat program lebih mudah dipahami. Persistent data structure di baliknya berbagi struktur agar tetap efisien.
  • Primitif konkurensi yang praktis. Atom, ref, agent — Clojure menyediakan beberapa model konkurensi, masing-masing cocok untuk pola yang berbeda. Ini bukan keanggunan teoretis semata; ini berasal dari pengalaman langsung Hickey dengan rasa sakit state mutable bersama di aplikasi Java produksi.
  • ClojureScript. Clojure dikompilasi ke JavaScript, sehingga bisa mengakses ekosistem browser dan Node.js. Tulis backend dengan Clojure, frontend dengan ClojureScript, dan bagikan kode di antara keduanya. Janjinya sama seperti TypeScript atau Kotlin Multiplatform, tapi hadir lebih awal.

Yang Dipinjam Bahasa Modern

Meski kamu tidak pernah menulis baris Lisp pun, kamu memakai ide-idenya setiap hari. Pengaruhnya begitu meluas sehingga melacaknya menjadi latihan untuk melihat seberapa dalam pengaruh itu.

map, filter, dan reduce di JavaScript adalah turunan langsung dari fungsi pemrosesan list Lisp — bahasa itu bahkan dinamai dari situ (LISt Processing). List comprehension di Python adalah gula sintaksis untuk operasi yang sama. Pattern matching di Rust berakar melalui ML hingga ke ekspresi cond di Lisp. Closure di Swift, sintaks lambda di Kotlin, API streams di Java — semuanya adalah konsep Lisp yang memakai pakaian berbeda.

Sistem macro di Rust (macro_rules! dan procedural macro), Elixir, Nim, dan Julia semuanya terinspirasi langsung dari macro Lisp — meski tidak ada yang benar-benar semulus itu karena tidak ada bahasa tersebut yang memiliki sintaks homoiconic. Ketika kode adalah data, macro menjadi sepele. Ketika kode punya sintaks yang kompleks, macro harus mem-parse dan menghasilkan sintaks itu, dan itu menambah gesekan.

Pengembangan berbasis REPL sudah menjadi norma di data science (notebook Jupyter pada dasarnya adalah REPL dengan persistensi), dan alat seperti Figwheel serta shadow-cljs membawa hot-reloading ke frontend — gagasan yang datang langsung dari tradisi Lisp dalam mengembangkan terhadap sistem yang sedang berjalan.

Apakah Kamu Perlu Belajar Lisp?

Jawaban jujurnya bergantung pada apa yang ingin kamu dapatkan darinya.

Jika kamu ingin menjadi programmer yang lebih baik dengan memperluas cara berpikirmu tentang kode: ya, tentu saja. Belajar Lisp — khususnya belajar berpikir dalam transformasi data, struktur rekursif, dan kode sebagai data — akan mengubah cara kamu mendekati masalah di bahasa apa pun. Mirip dengan belajar functional programming: meski kamu tidak pernah memakai Haskell di produksi, konsepnya membuatmu menulis Python dan JavaScript yang lebih baik.

Jika kamu ingin membangun perangkat lunak produksi dengan Lisp: Clojure adalah pilihan praktisnya. Ia punya ekosistem nyata, komunitas profesional, dan perusahaan (Nubank, Walmart, CircleCI) yang menjalankannya dalam skala besar. Common Lisp masih layak tetapi niche — kamu akan lebih banyak menghabiskan waktu pada infrastruktur dan lebih sedikit pada masalah utamamu. Scheme dan Racket sangat baik untuk pendidikan dan riset bahasa, tapi kurang praktis untuk pengembangan serbaguna.

Jika kamu penasaran tapi belum siap berkomitmen, baca kode Clojure. Bukan tutorial — melainkan kode produksi sungguhan. Perhatikan bagaimana developer Clojure menyusun fungsi-fungsi kecil, bagaimana mereka memakai threading macro (-> dan ->>>) untuk membangun pipeline data, bagaimana mereka memodelkan domain dengan map biasa alih-alih class. Kamu akan melihat gaya pemrograman yang lebih ringkas, lebih komposabel, dan lebih berfokus pada aliran data dibanding yang biasa kamu temui di basis kode OOP mainstream.

Daya tahan Lisp bukanlah nostalgia. Ia adalah hasil dari keberhasilan menata beberapa hal fundamental dengan sangat tepat, sehingga enam dekade desain bahasa belum mampu memperbaikinya. Tanda kurungnya memang aneh. Ekosistemnya lebih kecil dari yang kamu inginkan. Tapi ide-idenya abadi, dan jika kamu meluangkan waktu untuk mempelajarinya, kamu akan mendapati dirimu menulis kode yang lebih baik di bahasa apa pun yang kamu pakai sehari-hari.