Xah Lee, 2005-10, 2009-11-19
This page is a brief, practical, tutorial 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 after the 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 lisp code, 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”). To find the documentation of a function in the official GNU Emacs Lisp Reference Manual, type “Alt+x elisp-index-search”.
; 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
Note: You can see all past output from “message” in the buffer named “*Messages*”. You can switch to it by “Alt+x switch-to-buffer”.
(+ 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
WARNING: When you need to input a float, you need to include a zero after the decimal. A single decimal without zero is still integer. So, “(/ 7 2.)” returns 3, not 3.5, because emacs think both numbers are integer, and the “/” function will return the integer part of the quotient when both argument are integer type.
;; float must have a 0 followed by a dot (integerp 3.) ; returns t (floatp 3.) ; returns nil (floatp 3.0) ; returns t
Function names that ends with a “p” often means it returns either true or false. The “p” stands for “predicate”.
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
There is no “boolean datatype” in elisp. Just remember that “nil” and “()” is false, everything else is true.
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.0) ; ⇒ t
Comparing strings:
(string= "this" "this") ; ⇒ t. Case matters. (string< "a" "b") ; ⇒ t. by lexicographic order. (string< "B" "b") ; ⇒ t.
To test if two symbols have the same datatype and value, use “equal”.
;; testing if two values have the same datatype and value. (equal "abc" "abc") ; ⇒ t (equal 3 3) ; ⇒ t (equal 3.0 3.0) ; ⇒ t (equal 3 3.0) ; ⇒ nil. Because datatype doesn't match. ;; testing equality of lists (equal '(3 4 5) '(3 4 5)) ; ⇒ t (equal '(3 4 5) '(3 4 "5")) ; ⇒ nil ;; testing equality of symbols (equal 'abc 'abc) ; ⇒ t
There is no “!=” or “not-equal”. To test for inequality, use “not” to negate your equality test.
(not (= 3 4)) ; ⇒ t (not (equal 3 4)) ; ⇒ t
(info "(elisp) Comparison of Numbers")
(info "(elisp) 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.
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 expression. 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”.
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
(info "(elisp) 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)))
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))))
Note: There is no “for” loop construct.
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 (assuming they are variables you have defined), use: “(list x y z)”.
; prints a list (message "%S" '(a b c)) ; assign a list to a var (setq mylist '(a b c)) ; create 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) | first element |
| (nth n mylist) | nth element (start from 0) |
| (car (last mylist)) | last element |
| (cdr mylist) | 2nd to last elements |
| (nthcdr n mylist) | nth to last elements |
| (butlast mylist n) | without 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) | number of elements |
| (cons x mylist) | add x to front |
| (append mylist1 mylist2) | join two lists |
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.
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 list (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 "/home/vicky/web/3d/viz.html" "/home/vicky/web/3d/viz2.html" "/home/vicky/web/dinju/Khajuraho.html" "/home/vicky/web/dinju/Khajuraho2.html" "/home/vicky/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 returns 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 the function won't be available when user types “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 cursor position." (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 (myArg) "Prints the argument" (interactive "p") (message "Your argument is: %d" myArg) )
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 into a command that can be called by “Alt+x”. A function with the “(interactive)” clause is called a command. The “(interactive ‹x›)” form takes a single-letter code x to indicate how the command gets its arguments from user. There are about 30 codes for the x, but the most useful are the following:
Here is a function definition template that almost all elisp functions use:
(defun myFunction (arg1 arg2 ...) "‹One sentence summary of what this command do.› More detailed documentation if necessary here..." (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.)
(info "(elisp) Defining Functions")
(info "(elisp) Defining Commands")
LISP differs from most imperative programing languages such as C, Java, Perl, 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, variable'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: