Membuka bahasa jantung Emacs: mengenal s-expression dan struktur list, menulis fungsi dengan defun dan variabel dengan defvar, mengevaluasi ekspresi dengan C-x C-e, memakai buffer *scratch* sebagai playground, dan menulis fungsi kustom pertama yang langsung dipakai di sesi Emacs.

Hingga episode 8, kalian memakai Emacs sebagai pengguna. Episode 9 adalah gerbang menuju level berikutnya: membaca dan menulis Emacs Lisp (Elisp) — bahasa yang menggerakkan seluruh editor. Ini yang membedakan "pengguna Emacs" dari "penghuni Emacs".
Kenapa penting? Karena hampir semua kustomisasi yang akan kita bangun di 20 episode berikutnya — init file (episode 10), paket sendiri (episode 26), tuning performa (episode 27) — adalah Elisp. Tanpa membaca Elisp, kalian hanya akan menyalin config dari internet tanpa paham. Dengan dasar ini, kalian akan menulis config sendiri.
Elisp adalah bahasa Lisp — kode ditulis sebagai s-expression (symbolic expression): list yang dibungkus kurung, dengan operator di depan:
(+ 1 2) ; penjumlahan
(- 10 4) ; pengurangan
(concat "hello" " " "emacs") ; gabung string
(format "x = %d" 42) ; format ala printfAturan baca: fungsi pertama, argumen berikutnya. (+ 1 2 3) = 1 + 2 + 3. Inilah "prefix notation" — semua operator adalah fungsi biasa.
Struktur dasar Elisp:
42), string ("teks"), symbol (t, nil, setq).(a b c) — urutan elemen dalam kurung.' : mencegah evaluasi — '(a b c) berarti "list yang berisi symbol a b c", bukan "panggil fungsi a".'(1 2 3) ; list literal
(list 1 2 3) ; sama, via fungsi list
(setq x '(1 2 3)) ; simpan list ke variabel xt dan nil adalah kebenaran Lisp: t benar, nil salah (dan juga list kosong). Ini berbeda dari bahasa lain — nil punya dua peran.
Buffer *scratch* (dibuka default di Emacs) adalah tempat mengevaluasi Elisp tanpa risiko. Mode-nya lisp-interaction-mode. Jalur cepat evaluasi:
C-x C-e → eval-last-sexp: evaluasi s-expression sebelum pointKetik (+ 1 2) di *scratch*, letakkan point tepat setelah kurung tutup, tekan C-x C-e. Hasil 3 muncul di minibuffer.
Note
Selalu akhiri ekspresi dengan kurung penuh dan letakkan point di belakang kurung tutup sebelum C-x C-e. Kebiasaan evaluasi cepat ini akan kalian pakai ratusan kali di episode 10 dan 26.
defun mendefinisikan fungsi. Sintaksnya:
(defun nama-fungsi (argumen...)
"Dokumentasi satu baris."
(badan-fungsi...))Fungsi kustom pertama:
(defun hello (nama)
"Sapa seseorang."
(message "Halo, %s!" nama))Evaluasi dengan C-x C-e, lalu panggil:
(hello "developer")message mencetak ke minibuffer dan buffer *Messages*. Fungsi ini sudah bisa dipanggil dari M-x juga — ketik M-x hello RET dan Emacs meminta argumen nama di minibuffer.
Fungsi Lisp mengembalikan nilai ekspresi terakhir:
(defun tambah-satu (n)
"Kembalikan n + 1."
(+ n 1))
(tambah-satu 41) ; → 42setq mengubah nilai variabel (boleh belum ada).defvar mendefinisikan variabel dengan dokumentasi — cara yang benar untuk variabel "pengaturan".(setq my-name "alice") ; set tanpa dokumentasi
(defvar my-greeting "Halo"
"Sapaan default yang dipakai fungsi hello.") ; set + docstringdefvar juga tidak menimpa nilai yang sudah ada — sifat penting untuk variabel paket (definisi ulang tidak menghapus nilai yang diset pengguna).
Elisp memakai if, when, unless, dan predicates (fungsi berakhiran ?):
(if (> 3 2)
"tiga lebih besar"
"dua lebih besar")
(when (string= "a" "a") "kondisi benar")
(unless nil "nil itu false")
(stringp "teks") ; t — string?
(numberp 42) ; t — angka?
(zerop 0) ; t — nol?when untuk satu kasus saja, if untuk dua cabang, unless kebalikan when. Ini cukup untuk 90% logika config Emacs.
lambda membuat fungsi anonim; mapcar menerapkannya ke tiap elemen list:
(mapcar (lambda (x) (* x x)) '(1 2 3 4))
; → (1 4 9 16)Kombinasi lambda + mapcar muncul terus di config modern — misalnya menambahkan hook ke banyak mode sekaligus di episode 26.
Gabungkan semua konsep — fungsi yang menyapa berdasarkan waktu:
(defun sapa-waktu (nama)
"Sapa NAMA sesuai jam saat ini."
(let* ((jam (string-to-number (format-time-string "%H")))
(sapaan (cond
((< jam 12) "Selamat pagi")
((< jam 17) "Selamat siang")
(t "Selamat malam"))))
(message "%s, %s!" sapaan nama)))
(sapa-waktu "budi") ; evaluasi → sesuai jam sekaranglet* mengikat variabel lokal, cond adalah if berantai, format-time-string mengambil jam. Semua fungsi ini — string-to-number, cond, let* — bisa diselidiki dengan C-h f dari episode 8.
electric-pair-mode (auto-close kurung). Aktifkan di *scratch*: M-x electric-pair-mode.setq pada variabel sistem: jangan setq variabel yang seharusnya diset dengan customize-set-variable — terutama yang ber-docstring "user option". Episode 10 memperkenalkan pola use-package yang menanganinya.(message ...) di tengah config yang sering dievaluasi: pesan akan membanjiri *Messages*. Pakai message hanya untuk debugging.defun) aman — evaluasi ulang hanya mendefinisikan ulang.Pada episode 9 ini, kalian telah membaca dan menulis Elisp pertama.
Inti yang harus dibawa pulang:
' untuk quote.defun mendefinisikan fungsi + docstring; defvar variabel + docstring; setq ubah nilai.C-x C-e mengevaluasi ekspresi di *scratch* — playground tercepat.when/if/cond, lambda, mapcar, let* — cukup untuk config sehari-hari.C-h f — tidak perlu menghafal.Di episode 10 selanjutnya, kita membangun fondasi permanen: init config & use-package — struktur ~/.emacs.d/init.el, kenapa use-package menjadi standar sejak Emacs 29, pola custom-set-variables, dan membaca error lewat C-h e. Sampai jumpa di episode 10!