Elisp For Clojure Developers
This is not a blog post, but a continually updated resource. Last updated on 19th June 2025.
My magic wand wish would have been to use clojure to script emacs. But not all dreams can come true, learning bits and pieces of elisp over the years have paid dividends to me.
I would argue that you no longer need to _learn_ elisp the way you had to previously, with LLMs a lot of code can be generated but you still need to understand the fundamaentals.
As a clojure developer, the best way to learn elisp fundamaentals is to compare them with Clojure. This document will try to do exactly that, it will compare Clojure and Emacs Lisp across syntax, semantics, and standard libraries. Also tips, tricks, and TIL’s I come across.
Data Structures and Types
Numbers and Scalars
- Clojure supports integers, floating-point, and rational numbers (e.g.
3/2
). - Emacs Lisp has only integers and floats.
;; clojure
(+ 1 1.0) ;; => 2.0
(/ 3 2) ;; => 1 (integer division)
;; elisp
(+ 1 1.0) ; => 2.0
(/ 3 2) ; => 1
Strings and Characters
;; clojure
(str "hello, " "world") ;; => "hello, world"
;; character
\a ;; => \a
;; elisp
(concat "hello, " "world") ; => "hello, world"
;; character
?a ;; => 97
Booleans and Truthiness
- Clojure:
true
,false
,nil
- Elisp:
t
(true),nil
(false and empty list)
;; clojure
(if "" :yes :no) ;; => :yes
(if true :yes :no) ;; => :yes
(if nil :yes :no) ;; => :no
;; elisp
(if "" :yes :no) ;; => :yes
(if t :yes :no) ;; => :yes
(if nil :yes :no) ;; => :no
Lists and Sequences
;; clojure
(def ox-list '(1 2 3))
(first ox-list) ;; => 1
(rest ox-list) ;; => (2 3)
;; elisp
(setq ox-list '(1 2 3))
(car ox-list) ; => 1
(cdr ox-list) ; => (2 3)
Vectors (Arrays)
[1 2 3] ;; vector
(vector 1 2 3) ; => [1 2 3]
Hash Maps and Alists
{:a 1 :b 2}
(get {:a 1 :b 2} :a) ;; => 1
(setq al '((a . 1) (b . 2)))
(cdr (assoc 'a al)) ; => 1
Sets
- Clojure:
#{1 2}
- TODO: elisp
Functions and Variables
Function Definitions
(defn add [x y] (+ x y))
(defun add (x y)
(+ x y))
Arity and Arguments
(defn greet
([] (greet "World"))
([name] (str "Hello, " name)))
(defun greet (&optional name)
"Greet NAME or default to \"World\"."
(let ((name (or name "World")))
(concat "Hello, " name)))
Anonymous Functions
(map #(inc %) [1 2 3])
(mapcar (lambda (x) (+ x 1)) '(1 2 3))
Variables
(def x 10)
(let [x 5] ...)
(defvar x 10)
(setq x 5)
(let ((y 3)) (+ x y))
Control Flow
Conditionals
(if (even? x) :even :odd)
(if (evenp x) 'even 'odd)
let and Binding
(let [x 1 y 2] (+ x y))
(let ((x 1) (y 2)) (+ x y))
Sequential Execution
(do (println "one") (println "two"))
(progn (message "one") (message "two"))
Macros
Defining Macros
(defmacro unless [pred & body]
`(if (not ~pred) (do ~@body)))
(defmacro unless (pred &rest body)
`(if (not ,pred)
(progn ,@body)))
Syntax Quoting
- Clojure: ```,
~
,~@
- Elisp:
`
,,
,,@
Concurrency and State
Clojure
(def counter (atom 0))
(swap! counter inc)
Emacs Lisp
(setq th (make-thread (lambda () (message "Hello"))))
(thread-join th)
Namespaces and Libraries
Namespaces
- Clojure:
(ns my.ns ...)
- Elisp:
(provide 'my-lib)
,(require 'my-lib)
Standard Libraries
seq.el
: sequence functions (seq-map
,seq-filter
)cl-lib
: optional CL functions (cl-loop
,cl-remove-if
)subr-x
: modern extensions (string-join
,when-let
)
Operation | Clojure | Emacs Lisp |
---|---|---|
map/filter/reduce | map , filter |
seq-map , seq-filter |
assoc/update | assoc , update |
setf , alist-get , puthash |
concat strings | str |
concat , format , string-join |
Summary
Clojure Core Function | Clojure Example | Emacs Lisp Example |
---|---|---|
map |
(map inc [1 2 3]) |
(mapcar #'1+ '(1 2 3)) |
reduce |
(reduce + [1 2 3 4]) |
(apply #'+ '(1 2 3 4)) |
filter |
(filter even? [1 2 3 4]) |
(seq-filter #'evenp '(1 2 3 4)) |
first |
(first [1 2 3]) |
(car '(1 2 3)) |
rest |
(rest [1 2 3]) |
(cdr '(1 2 3)) |
cons |
(cons 0 [1 2 3]) |
(cons 0 '(1 2 3)) |
conj |
(conj [1 2] 3) |
(append '(1 2) '(3)) |
nth |
(nth [10 20 30] 1) |
(nth 1 '(10 20 30)) |
count |
(count [1 2 3]) |
(length '(1 2 3)) |
assoc |
(assoc {:a 1} :b 2) |
(alist-put '(:a . 1) :b 2) |
This guide should help Clojure developers understand and adapt to Elisp idioms and semantics.
References: Emacs Lisp Manual, Clojure.org, built-in Emacs libraries.