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
(+ 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
(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

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

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

Standard Libraries

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.