Emacs Lisp Basics

By Xah Lee. Date: . Last updated: .

This page is a short, practical, tutorial of Emacs Lisp the language.

To evaluate elisp code, for example, type (+ 3 4), then move your cursor to after the closing parenthesis, then call eval-last-sexpCtrl+x Ctrl+e】. Emacs will evaluate the lisp expression to the left of the cursor.

Alternatively, you can select the lisp code, then Alt+x eval-region.

Alternatively, you can Alt+x ielm. It will start a interactive elisp command line interface.

To find the doc string of a function, Alt+x describe-functionCtrl+h f】. (If the word under cursor is a function, emacs will lookup that by default, saves typing.)

emacs lisp eval 2017 01 04
eval emacs lisp code basics. [see Evaluate Emacs Lisp Code]


; printing
(message "hi")

; printing variable values
(message "Her age is: %d" 16)        ; %d is for number
(message "Her name is: %s" "Vicky")  ; %s is for string
(message "My list is: %S" (list 8 2 3))  ; %S is for any lisp expression

You can see the output in the buffer named “*Messages*”. You can switch to it by Alt+x view-echo-area-messagesCtrl+h e】.

More detail: Emacs Lisp's print, princ, prin1, format, message.


(+ 4 5 1)  ; 10
(- 9 2)    ; 7
(- 9 2 3)  ; 4
(* 2 3)    ; 6
(* 2 3 2)  ; 12

;; integer part of quotient
(/ 7 2)    ; 3

;; division
(/ 7 2.0)  ; 3.5

;; mod, remainder
(% 7 4)    ; 3

;; power; exponential
(expt 2 3) ; 8

WARNING: single digit decimal number such as 2. needs a zero after the dot, like this: 2.0. For example, (/ 7 2.) returns 3, not 3.5.

;; 3. is a integer, 3.0 is a float
(integerp 3.) ;  t
(floatp 3.) ;  nil
(floatp 3.0) ;  t

Function names that end with a “p” often means it return either true or false. (The “p” stands for “predicate”) t means true; nil means false.

Convert Float/Integer

;; int to float
(float 3) ; 3.0

(truncate 3.3) ; 3

(floor 3.3) ; 3

(ceiling 3.3) ; 4

(round 3.4) ; 3

(info "(elisp) Numeric Conversions")

Convert String and Number

(string-to-number "3")
(number-to-string 3)

You can also use format to convert number to string. [see Elisp: print, princ, prin1, format, message]

(info "(elisp) Numbers")

True, False

In elisp, the symbol nil is false, anything else is considered true. Also, nil is equivalent to the empty list (), so () is also false.

;; all the following are false. They all evaluate to “nil”
(if nil "yes" "no") ;  "no"
(if () "yes" "no") ;  "no"
(if '() "yes" "no") ;  "no"
(if (list) "yes" "no") ;  "no", because (list) eval to a empty list, same as ()

By convention, the symbol t is used for true.

(if t "yes" "no") ;  "yes"
(if 0 "yes" "no") ;  "yes"
(if "" "yes" "no") ;  "yes"
(if [] "yes" "no") ;  "yes". The [] is vector of 0 elements

There is no “boolean datatype” in elisp. Just remember that nil and empty list () are false, anything else is true.

Boolean Functions

Here's and and or.

(and t nil) ;  nil
(or t nil) ;  t

;; can take multiple args
(and t nil t t t t) ;  nil

Comparing numbers:

(< 3 4) ; less than
(> 3 4) ; greater than

(<= 3 4) ; less or equal to
(>= 3 4) ; greater or equal to

(= 3 3)   ;  t
(= 3 3.00000000000000001) ;  t

(/= 3 4) ; not equal. ⇒ t

Comparing strings:

;; compare string
(equal "abc" "abc") ;  t

;; dedicated function for comparing string
(string-equal "abc" "abc") ;  t

(string-equal "abc" "Abc") ;  nil. Case matters

;; can be used to compare string and symbol
(string-equal "abc" 'abc) ;  t

For generic equality test, use equal. It tests if two values have the same datatype and value.

;; test if two values have the same datatype and value.

(equal 3 3) ;  t
(equal 3.0 3.0) ;  t

(equal 3 3.0) ;  nil. Because datatype doesn't match.

;; test equality of lists
(equal '(3 4 5) '(3 4 5))  ;  t
(equal '(3 4 5) '(3 4 "5")) ;  nil

;; test equality of strings
(equal "e" "e") ;  t

;; test equality of symbols
(equal 'abc 'abc) ;  t

There's also the function eq, it returns t if the two args are the same Lisp object. This is usually not what you want. (eq "e" "e") returns nil.

To test for inequality, the /= is for numbers only, and doesn't work for strings and other lisp data. Use not to negate your equality test, like this:

(not (= 3 4)) ;  t
(/= 3 4) ;  t. “/=” is for comparing numbers only

(not (equal 3 4)) ;  t. General way to test inequality.

even, odd

(= (% n 2) 0) ; test even

(= (% n 2) 1) ; test odd


Global Variables

setq is used to set variables. Variables need not be declared, and is global.

(setq x 1) ; assign 1 to x
(setq a 3 b 2 c 7) ; assign 3 to a, 2 to b, 7 to c

Local Variables

To define local variables, use let. The form is: (let (var1 var2 …) body) where body is (one or more) lisp expressions. The body's last expression's value is returned.

(let (a b)
 (setq a 3)
 (setq b 4)
 (+ a b)
) ;  7

Another form of let is this: (let ((var1 val1) (var2 val2) …) body). Example:

(let ((a 3) (b 4))
 (+ a b)
) ;  7

This form lets you set values to variable without using many setq in the body. This form is convenient if you just have a few simple local vars with known values.

(info "(elisp) Variables")

If Then Else

The form for “if” expression is: (if test body).

If you want a “else” part, the form is (if test true_body false_body).


(if (< 3 2) 7 8 ) ; 8

;; no false expression, return nil
(if (< 3 2) (message "yes") ) ; nil

(info "(elisp) Control Structures")

If you do not need a “else” part, you should use the function when instead, because it is more clear. The form is this: (when test expr1 expr2 …). Its meaning is the same as (if test (progn expr1 expr2 …)).

Block of Expressions

Sometimes you need to group several expressions together as one single expression. This can be done with progn.

(progn (message "a") (message "b"))
;; is equivalent to
(message "a") (message "b")

The purpose of (progn …) is similar to a block of code {…} in C-like languages. It is used to group together a bunch of expressions into one single parenthesized expression. Most of the time it's used inside “if”. For example:

(if something
    (progn ; true
    (progn ; else

progn returns the last expression in its body.

(progn 3 4 ) ; 4

(info "(elisp) Sequencing")


Most basic loop in elisp is with while.

(while test body)

, where body is one or more lisp expressions.

(setq x 0)

(while (< x 4)
  (print (format "number is %d" x))
  (setq x (1+ x)))
;; inserts Unicode chars 32 to 126
(let ((x 32))
  (while (< x 127)
    (insert-char x)
    (setq x (+ x 1))))

Usually it's better to use dolist or dotimes.

[see Elisp: Map / Loop Thru List / Vector]

(info "(elisp) Iteration")

Break/Exit a Loop

Elisp: Exit Loop/Function, catch/throw

Sequence, List, Vector

Elisp: Sequence: List, Array

Elisp: Vector

Elisp: List

Define a Function

Basic function definition is of the form:

(defun function_name (param1 param2 …) "doc_string" body)


(defun myFunction ()
  (message "Yay!"))

When a function is called, the last expression in the function's definition body is returned. (there's no “return statement”.)

(info "(elisp) Defining Functions")

Define a Command

A command is a function that emacs user can call by execute-extended-commandAlt+x】.

When a function is also a command, we say that the function is available for interactive use.

To make a function available for interactive use, add (interactive) right after the doc string.

Evaluate the following code. Then, you can call it by execute-extended-commandAlt+x

(defun yay ()
  "Insert “Yay!” at cursor position."
  (insert "Yay!"))

(info "(elisp) Defining Commands")

Here is a function definition template that majority of elisp commands follow:

(defun myCommand ()
  "One sentence summary of what this command do.

More detailed documentation here."
  (let (localVar1 localVar2 …)
    ; do something here …
    ;     ; last expression is returned

See also:

Emacs Lisp Basics

  1. Emacs Lisp Basics
  2. Overview of Text-Processing in Emacs Lisp
  3. Emacs Lisp Examples
  4. Evaluate Emacs Lisp Code
  5. Elisp: Documentation Lookup
  6. Elisp: Search Documentation
  7. Emacs: How to Edit Lisp Code
Patreon me $5 patreon

Or Buy Xah Emacs Tutorial

Or buy a nice keyboard: Best Keyboard for Emacs

If you have a question, put $5 at patreon and message me.