Xah Lee, 2005-10
This page is a brief, practical, overview of Emacs Lisp the language.
To evaluate a elisp code, type a elisp code in a blank file. For example, type “(+ 3 4)”, then move your cursor to the right of the last closing parenthesis, and type “Alt+x eval-last-sexp”. Emacs will evaluate the lisp expression to the left of the cursor. The keyboard shortcut is “Ctrl+x Ctrl+e”. Alternatively, you can select the region, then type “Alt+x eval-region”.
Alternatively, you can type “Alt+x ielm”, which turns the buffer into a interactive elisp command line interface.
To find the inline documentation of a function, type “Alt+x describe-function” (shortcut “Ctrl+h f”) then the function name. To find the documentation of a function in the official GNU Emacs Lisp Reference Manual, type “Alt+x elisp-index-search”, then the function name.
; 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 "Her mid init is: %c " 86) ; %c is for character in ascii code
(+ 4 5 1) ; ⇒ 10 (- 9 2) ; ⇒ 7 (- 9 2 3) ; ⇒ 4 (* 2 3) ; ⇒ 6 (* 2 3 2) ; ⇒ 12 (/ 7 2) ; ⇒ 3 Integer part of quotient (/ 7 2.0) ; ⇒ 3.5 (% 7 4) ; ⇒ 3. Remainder
Reference: Elisp Manual: Numbers.
In elisp, the symbol “nil” is false, everything else is considered true, including 0. Also, “nil” is a synonym for the empty list “()”, so “()” is also false.
By convention, the symbol “t” is used for true.
(and t nil) ; ⇒ nil (or t nil) ; ⇒ t
Comparing numbers:
(< 3 4) ; greater than (> 3 4) ; less than (<= 3 4) ; greater or equal to (>= 3 4) ; less or equal to (= 3 4) ; equality
Comparing strings (by lexicographic order. Case matters.):
(string= "this" "this") ; ⇒ t (string< "a" "b") ; ⇒ t
To test if two symbols have the same value, use “equal”.
(setq x 3) (setq y 3) (equal x y) ; ⇒ t
Reference: Elisp Manual: Comparison-of-Numbers.
Reference: Elisp Manual: Equality-Predicates.
“setq” is used to set variables. It has the form “(setq var1 val1 var2 val2 ...)”.
In lisp, variables need not be declared, and is global.
(setq x 1) (setq a 3 b 2 c 7) ; sets a to 3, b to 2, c to 7
To define local variables, use “let”. The form is: “(let (var1 var2 ...) body )” where “body” is other lisp expressions. The body's last expression's value is returned.
(let (a b) (setq a 3) (setq b 4) (+ a b) ) ; returns 7
Another form of “let” is this: “(let ((var1 val1) (var2 val2) ...) body )”. Example:
(let ((a 3) (b 4)) (+ a b) ) ; returns 7
This form lets you set values to variable without using a several “setq” in the body. This form is convenient if you just have a few simple local vars with known values.
Reference: Elisp Manual: Variables.
Sometimes you need to group several expressions together. This can be done with “progn”. For example, this code:
(progn (message "hi") (message "lo"))
is equivalent to
(message "hi") (message "lo")
“(progn ...)” is equivalent to a block of code “{...}” in C-like languages. It is used as argument to functions that takes only one expressson. For example, in this code: “(if something (progn this that) )”. If you leave out the “progn” and have “(if something this that)”, then it means “if true do this else do that”, but what you wanted is “if true do this_and_that”.
Reference: Elisp Manual: Sequencing.
The form for if statement is: “(if test then else)”. The “else” part is optional. Examples:
(if (< 3 2) (message "yes") ) (if (< 3 2) (message "yes") (message "no") ) (if nil (message "yes") (message "no") ) ; prints no
Reference: Elisp Manual: Control-Structures.
The following code shows a loop using the “while” function. The form is: “(while test do1 do2 ...)”.
(setq x 0) (while (< x 4) (princ (format "yay %d." x)) (setq x (1+ x)))
There are also “dotimes” and “dolist”.
Reference: Elisp Manual: Iteration.
In the following sample code, it inserts unicode chars 32 to 128. First, it sets a local variable x to 32. Then it starts a “while” loop, insert the corresponding unicode char, then increase x by 1.
(let ((x 32)) (while (/= x 128) (ucs-insert x) (setq x (+ x 1))))
Lists in lisp is like this: “ '(x y z) ”. The apostrophe in front of the paren is important. It prevents symbols in the list being evaluated. Don't worry if you don't understand what this means. Just think of it as particular syntax for lists.
Note: if you do want the symbols to be evaluated (assumping they are variables you have defined), use: “(list x y z)”.
; prints a list (message "%S" '(a b c)) ; assigne a list to a var (setq mylist '(a b c)) ; creat a list of values of variables (let ((x 3) (y 4) (z 5)) (message "%S" (list x y z)) ) ; prints "(3 4 5)"
| Function | Purpose |
|---|---|
| (car mylist) | Returns the first element of mylist. |
| (nth n mylist) | Returns the nth element of mylist (first element is indexed as 0 here). |
| (car (last mylist)) | Returns the last element of mylist. |
| (cdr mylist) | Returns a list that is made up from 2nd to last elements of mylist. |
| (last mylist) | Returns a list with one element; which is the last element of mylist. |
| (nthcdr n mylist) | Returns a list that's made up from nth to last elements of mylist. |
| (butlast mylist n) | Returns a list with out the last n elements. |
Here's some example of lists and element extraction.
(car (list "a" "b" "c") ) ; ⇒ "a" (nth 1 (list "a" "b" "c") ) ; ⇒ "b" (car (last (list "a" "b" "c")) ) ; ⇒ "c" (cdr (list "a" "b" "c") ) ; ⇒ ("b" "c")
| Function | Purpose |
|---|---|
| (length mylist) | Returns the number of elements. |
| (cons ele mylist) | Returns a list with ele prepended to mylist. |
| (append mylist1 mylist2) | Returns a list that's mylist1 and mylist2 joined. |
Examples:
(length (list "a" "b" "c") ) ; ⇒ 3 (cons "a" (list "c" "d") ) ; ⇒ ("a" "c" "d") (cons (list "a" "b") (list "c" "d") ) ; ⇒ (("a" "b") "c" "d") (append (list "a" "b") (list "c" "d") ) ; ⇒ ("a" "b" "c" "d")
| Function | Purpose |
|---|---|
| (pop mylist) | Remove first element from the variable. Returns the removed element. |
| (nbutlast mylist n) | Remove last n elements from the variable. Returns the new value of the variable. |
| (setcar mylist x) | replaces the first element in mylist with x. Returns x. |
| (setcdr mylist x) | replaces the rest of elements in mylist with x. Returns x. |
Don't worry if you don't understand the weird names like “car”, “cdr”, and “cons”. They are like that for historical reasons. You don't need to understand them for writing simple scripts.
Reference: Elisp Manual: Lists.
Here's a typical way of going thru a list. It is done with “mapcar”.
; add one to each list member (mapcar (lambda (x) (+ x 1)) '(1 2 3 4)) ; ⇒ (2 3 4 5) ; add one to each list member using the build in function 1+ (mapcar '1+ '(1 2 3 4)) ; ⇒ (2 3 4 5) ; take the 1st element of each element in the ilst (mapcar 'car '((1 2) (3 4) (5 6))) ; ⇒ (1 3 5) ; take the 2nd element of each element in the ilst (mapcar (lambda (x) (nth 1 x)) '((1 2) (3 4) (5 6))) ; ⇒ (2 4 6) ; apply a file processing function to a list of files (mapcar 'my-update-html-footer (list "/Users/xah/web/3d/viz.html" "/Users/xah/web/3d/viz2.html" "/Users/xah/web/dinju/Khajuraho.html" "/Users/xah/web/dinju/Khajuraho2.html" "/Users/xah/web/dinju/Khajuraho3.html" ) )
The “lambda” above pretty much means “subroutine”. It essentially let you define a function in the middle of your code. The form is “(lambda arguments body)”. For example, “(lambda (x y) (+ x y))” would be a function that takes two arguments, x and y, and return their sum.
Another common form to loop thru a list is using the “while” function. In each iteration, “pop” is used to reduce the list. Here's a example of going thru a list using the “while” function.
(let (mylist) (setq mylist '(a b c)) (while mylist (message "%s" (pop mylist)) (sleep-for 1) ) )
Following is another example of using “while” to loop thru a list.
; pop head of mylist ; prepend it to mylist2 ; resulting a reversed list (let (mylist mylist2) (setq mylist '(a b c)) (setq mylist2 '()) (while mylist (setq mylist2 (cons (pop mylist) mylist2) ) ) mylist2 )
First, use “let” to set a code block, with temporary variables “mylist” and “mylist2”. “mylist” is then set to “ '(a b c)”. “mylist2” is set to a empty list. Then, in the body of “while”, the “(pop mylist)” drops mylist's first element and returns it, the “(cons (pop mylist) mylist2)” creates a list with the new element prepended to “mylist2”. (Note: This code is to illustrate going thru a list. If you want to reverse a list, use the “reverse” function.)
Basic function definition is of the form: (defun functionName (param1 param2 ...) "doc string" body) . Example
(defun myFunction () "testing" (message "Yay!") )
This function can be called in other places in a elisp program but it is not visible to emac users. That is, the function won't be available for “Alt+x”. To make a function available for interactive use, add the “(interactive)” right after the doc string.
The following is a basic function definition for interactive use. The function takes no argument. Evaluate the following code. Then, you can call it by “Alt+x yay”
(defun yay () "insert \"Yay!\" at point." (interactive) (insert "Yay!"))
The following is a basic function definition, taking one argument from “Ctrl+u”. You can call it by typing “Ctrl+u 7 Alt+x myFunction”.
(defun myFunction (var1) "prints the argument" (interactive "p") (message "your argument is: %d" var1) )
The following is a basic function definition taking region as arg. Note the “(interactive "r")”. The “"r"” is a code that tells emacs that the function will receive the buffer's region as its argument.
(defun myFunction (myStart myEnd) "prints region start and end positions" (interactive "r") (message "Region begin at: %d, end at: %d" myStart myEnd) )
In summary, the “(interactive)” clause makes your function for interactive use. A function with the “(interactive)” clause is called a command. The “(interactive x)” form takes one string argument x to indicate how the command gets its arguments from user. There are about 50 code for “interactive”, but the most useful is the following:
Here is a function definition template that almost all elisp functions use:
(defun myFunction (arg1 arg2 ...) "does this and that ..." (interactive) (let (localVar1 localVar2 ...) ; do something here... ; ... ; last expression is returned ) )
When a function is called, the last expression in the function's definition body is returned. (You do not have to write “return ...” as in other languages.)
Reference: Elisp Manual: Defining-Functions.
Reference: Elisp Manual: Defining-Commands.
LISP differs from most imperative programing languages in that it deals with symbols, as opposed to just variables and values.
In practice, this means that in lisp, variables can be manipulated in its un-evaluated state. The situation is like the need for the “evaluate” command in many languages, where the programer can built code as strings and do “evaluate(myCodeString)” to achieve meta-programing. In lisp, variables's unevaluated form are always available. You just put a apostrophe in front of it. This is why variables in lisp are called symbols. This makes meta-programing more powerful.
For example, in most languages, once you defined “x=3”, you cannot manipulate the variable “x” because it gets evaluated to 3 right away. If you want, you have to build a string “"x"” and manipulate this string, then finally use something like “evaluate(myCodeString)” to achieve the effect. In most languages, the use of “evaluate()” breaks down quickly because the language is not designed for doing it. It's extremely slow, and impossible to debug, and there lacks many facilities for such meta programing.
The ability to meta-program has many applications. For example, when you need to take user input as code (such as math formulas), or need to manipulate math expressions, or writing programs that manipulate source code. (e.g. XML transformation)
Related essays:
