Emacs Lisp Cheat Sheet for Clojure Developers

Robert JohnsonRobert Johnson
8 min read

Table of Contents

Numeric types

Elisp has integers and floats. These can be mixed in arithmetic functions how you'd usually expect:

(+ 1 1) ; => 2
(+ 1 1.0) ; => 2.0
(+ 1.0 1.0) ; => 2.0

It doesn't have Clojure's ratio type though, so integer division works similarly to most other languages:

(/ 3 2) ; => 1

Integers can be expressed in multiple ways; the printed representation of REPL output looks odd at first, but it's simply showing you the alternate representations of the integer (I've omitted this elsewhere for brevity):

16 ; => 16 (#o20, #x10, ?\C-p)
;; Shows decimal, octal, hex and character value
;; (see 'character types' section below)

Floats can be expressed in scientific notation:

1e2 ; => 100.0

Integers can be arbitrarily large;

(+ 1 10000000000000000000)
; => 10000000000000000001

Character types

Elisp has strings and characters. Strings are essentially arrays of characters. They are represented and escaped in much the same way as Clojure:

"This is a simple string"
"A newline character: \n"

"Escaped line breaks\
are ignored"
;; => "Escaped line breaks are ignored"

Character literals a displayed using a ? prefix:

(string ?f ?o ?o) ; => "foo"

Characters are in fact simply integers:

?A ; => 65 (#o101, #x41, ?A)
(string 102 111 111) ; => "foo"
(+ ?f ?o) ; => 213 (#o325, #xd5)

Though not all integers are valid characters:

(string 12356789) ; => error!

You can format strings much the same as in Clojure using the format function:

(format "I have %s bananas" 3)
;; => "I have 3 bananas"

You can also display messages (also with optional formatting elements) in the minibuffer using the message function.

(message "Hello, world!")
(message "Show a message to %s",
         "Alice")

Such messages are also sent to the *Messages* buffer, making message helpful for debugging.

Conditional logic

nil and the empty list '() are falsy; everything else is truthy:

(if nil "truthy" "falsey")
;; => "falsey"
(if '() "truthy" "falsey")
;; => "falsey"

(if "a" "truthy" "falsey")
;; => "truthy"
(if "" "truthy" "falsey")
;; => "truthy"
(if 1 "truthy" "falsey")
;; => "truthy"
(if 0 "truthy" "falsey")
;; => "truthy"

Elisp doesn't have a separate Boolean type with true and false values; instead, the symbol t is used to represent true and nil is used to represent false. Predicate functions conventionally have a p suffix (rather than ? as in Clojure):

(integerp 1) ; => t
(integerp 1.5) ; => nil

(Elisp will accept symbol names containing ?, so you can name your own predicates in the Clojure style if you want.)

Equality

= is specifically for checking comparisons on number types (integers & floats):

(= 1 1) ; => t
(= 2 2.0) ; => t
(= 3.0 3.0) ; => t

(= 1 2) ; => nil

(= 1 "a") ; => error!

string= is for comparing strings and characters. It is case sensitive:

(string= "a" "a") ; => t
(string= "a" 'a) ; => t

(string= "a" "b") ; => nil
(string= "a" "A") ; => nil

(string= 1 1) ; => error!

equal does value-based comparisons. It works for numbers & string types too, but it doesn't compare across ints & floats and strings & symbols like = & string= do. It too is case sensitive.

(equal 1 1) ; => t
(equal "a" "a") ; => t

(equal "a" "A") ; => nil
(equal 1 1.0) ; => nil

eq Performs reference-based equality (like Clojure's identical fn):

(eq "a" "a") ; => nil

(See Comparison Functions on the Emacs Wiki for further info.)

Functions

Functions are defined using defun. The arguments are enclosed in a parens (rather than in brackets):

(defun foo (x y)
  (+ x y))

Docstrings are a bit different in Elisp though:

  • they go after the argument list
  • line breaks are preserved, but so is any indentation-related whitespace; therefore the convention is to simply remove indentation for docstrings for all but the first line.
(defun foo (x y)
  "This is a docstring, continuing
onto the next line"
  (+ x y))

Variadic functions (AKA functions with "rest args") can be created using &rest:

(defun bar (x &rest r)
  (format "First arg: %s; rest: %s" x r))

(bar 1 2 3)
;; => "First arg: 1; rest: (2 3)"

You can't create true multi-arity functions in Elisp, but you can get close enough by using optional arguments:

(defun greet (person1 &optional person2)
  (if person2
      (message "Hello, %s and %s!"
               person1 person2)
    (message "Hello, %s!" person1)))

(greet "Alice")
;; => "Hello, Alice!"

(greet "Alice" "Bob")
;; => "Hello, Alice and Bob!"

Let forms

For let bindings, use let*. The bindings are placed in an (unquoted) list, and each binding pair has to be placed in its own list too:

(let* ((x 1)
       (y (+ 1 x)))
  (* 3 y)) ; => 6

let also exists, but it doesn't let you use earlier bindings within later ones:

(let ((x 1)
      (y (+ 1 x)))
  (* 3 y)) ; => error!

(let ((x 1)
      (y 2))
  (* 3 y)) ; => 6

Comments

(defmacro comment (&rest body)
  nil)

(comment
 (blow-up-the-world))

Namespaces and access modifiers

Emacs doesn't have namespaces, and so doesn't have access modifiers either.

By convention, packages prefix all their functions & variables with a prefix, packagename-; e.g. all functions in the org package are prefixed with org-.

You do still have to require packages in order to ensure they are loaded before using them. E.g. (require 'org) would ensure that the code for the org package is loaded. Depending on your emacs config / distribution, many packages may already be required for you.

Functions intended as private are by convention signified with an extra - in the prefix; e.g. org--get-local-tags is a private function in the org package.

Variables

Variables can be created & updated using setq (short for "set quoted"):

(setq my-variable 2)
(+ 1 my-variable) ; => 3

defvar will create a variable, but won't update it if it's already been set; you can basically think of it as Clojure's defonce:

(defvar cheese "brie")
(message "cheese = %s" cheese)
;; => "cheese = brie"

(defvar cheese "stilton")
(message "cheese = %s" cheese)
;; => "cheese = brie"

(setq cheese "stilton")
(message "cheese = %s" cheese)
;; => "cheese = stilton"

Symbols, values & lambdas

One of the more confusing parts of Elisp is that its symbols point to multiple storage locations; a single symbol can refer to both a function and a variable:

(setq baz 123)
(defun baz (x y)
  (- x y))

(message "baz as value: %s" baz)
;; => "baz as value: 123"

(baz 10 3)
;; => 7

This means that most of the time when passing around functions you have to quote them:

;; Not quoting + here - will error
(apply + '(1 2 3))
;; => error: (void-variable +)

;; Quoting + here - OK
(apply '+ '(1 2 3))
;; => 6

We can create anonymous functions using lambda - but because lambdas are stored in variables rather than defuns, you can't call them directly:

(let* ((times-2 (lambda (x) (* 2 x))))
  (times-2 3))
;; => error: (void-function times-2)

Instead, you need to use funcall:

(let* ((inc (lambda (x) (+ x 1)))
       (dec (lambda (x) (- x 1))))
  (message "result for inc: %s"
           (funcall inc 10))
  (message "result for dec: %s"
           (funcall dec 10)))
;; =>
;; result for inc: 11
;; result for dec: 9

Threading macros & higher-order functions

A lot of Clojure-style goodness can be provided by using the excellent dash package:

;; (if not installed already)
(package-install 'dash)

(require 'dash)

;; Threading macros:
(-> 10
    (+ 1)
    (* 2)) ; => 22

;; Higher order functions:
(let* ((inc (lambda (x)
              (+ x 1))))
  (-map inc '(1 2 3)))
;; => (2 3 4)

(let* ((evenp (lambda (n)
                (= 0 (% n 2)))))
  (-filter evenp '(1 2 3 4)))

Note that Emacs often has its own built-in versions for these - e.g. thread-first & thread-last for threading, mapcar as an equivalent to Clojure's map - but as a Clojurist you'll probably find what you're looking for quicker by using dash's functions instead.

False friends

concat

Elisp's concat not only concatenates but also converts everything received into a string:

(concat "foo" "bar")
;; => "foobar"

(concat '(65 66) '(67 68))
;; => "ABCD"

string

Elisp's string function - unlike Clojure's str - only works on characters:

(string ?f ?o ?o) ; => "foo"

(string "foo") ; => error!
(string "f") ; => error!
(string 1.0) ; => error!

It can operate on integers, but it converts them to the character corresponding to its charcode (assuming it has one):

(string 65) ; => "B"

(string 123456789) ; => error!

Aliases

You can create aliases using defalias:

(defun foo (x y)
  (+ x y))
(defalias 'bar #'foo)

(foo 3 1) ; => 4
(bar 3 1) ; => 4

NB we linked to the function cell of foo using #' above, so we can redef foo, and bar will pick up the change too:

(defun foo (x y)
  (- x y))
(foo 3 1) ; => 2
(bar 3 1) ; => 2

Suggested aliases

Here are some Clojure-style aliases for their Emacs builtin equivalents:

(defalias 'do 'progn)
(defalias 'when-not 'unless)

Going further

If you'd like to put some Elisp into practice, you could also check out my intro to extending Emacs using Elisp. The Awesome Elisp GitHub repo is also a great resource.

Acknowledgements

Thanks to ambirdsall, hvis & Philip Kaludercic for suggestions. See Reddit for discussion.

0
Subscribe to my newsletter

Read articles from Robert Johnson directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Robert Johnson
Robert Johnson