Emacs Lisp

Table of Contents

The names CAR and CDR derive from the history of Lisp. The original Lisp implementation ran on an IBM 704 computer which divided words into two parts, called the “address” part and the “decrement”; CAR was an instruction to extract the contents of the address part of a register, and CDR an instruction to extract the contents of the decrement. By contrast, “cons cells” are named for the function ‘cons’ that creates them, which in turn was named for its purpose, the construction of cells.

1 Evaluation

The read and evaluate is seperate. For example, (1 2 3) is a list, and can be read by lisp interpreter as an object: a list. But try to evalute it in emacs results in error. It is not because emacs cannot read it. It can, but it tries to evaluate it using a list form, which checks the car of list and treat it as a function. Of course '1' is not a function.

There's a form called self-evaluating form. It evaluate to itself. For example, the number, the string, evaluates to itself.

1.1 quoting

From the elisp info page:

The special form ‘quote’ returns its single argument, as written, without evaluating it. This provides a way to include constant symbols and lists, which are not self-evaluating objects, in a program. (It is not necessary to quote self-evaluating objects such as numbers, strings, and vectors.)

The expression \'print means read it without evaluation. So the following expression makes sense:

(eval (list 'prin1 '1))

Note that (quote x) and 'x are equivalent.

1.2 backquoting

It is identical to quoting except that it allows to evaluate part of the object. The special marker , can be used:

`(a list of ,(+ 2 3) elements)
; -> (a list of 5 elements)

If the partial evaluation returns a list, but you want to splice it with some other elements into a list, you can do it neatly with ,@:

(setq some-list '(2 3))
`(1 ,@some-list 4 ,@some-list)
;; -> (1 2 3 4 2 3)

Without this feature, you have to write some hard to understand code:

(cons 1 (append some-list '(4) some-list))
;; -> (1 2 3 4 2 3)

2 Basic

2.1 Interactive

print
print the object in quotes, with a newline before and after it
prin1
print the object in quotes without newlines
princ
print the object without quotes, without newlines
(no term)
message

2.2 Symbol

  • defvar
  • defun
  • defmacro

A symbol can not be both a function and macro, but it can be a variable and a function at the same time.

2.2.1 property list

A symbol can have a property list …

get symbol property
put symbol property value
symbol-plist symbol
return the p-list
setplist symbol plist

2.2.2 Variable

Dynamic binding: in the defun, we can refer to free variable. When calling the defun in different environment, it will get the variable from them. This is used by default.

(defvar x -99)
(defun getx () x)
(let ((x 1)) (getx)) ; -> 1
(getx) ; -> -99

Lexical is also introduced as optional feature.

3 Regular Expression

3.1 syntax

3.1.1 basics

symbol description
. match anything except a newline
*  
+  
?  
*?, +?, ?? non-greedy, match the smallest part
[]  
[^]  
^  
$  

3.1.2 Character classes

Use the double [[]] form. E.g. [[:ascii:]], and also the negative writes [^[:ascii:]].

symbol description
ascii 0-127
alnum letter or digit
alpha letter
blank space and tab
cntrl ASCII control char
digit 0-9
lower lower-case
upper upper-case
punct punctuation
space whitespace
word \w

3.1.3 Backslash

Backslash is also used in elisp read syntax. So when you want one \ in the string, you need to write double.

symbol description
\1 (pipe) either one of two expressions. Can be used in capturing group
\{\} {} counter part
\(\) capturing group
\(?:\) non-capturing group
\(?NUM:\) numbered capturing group.. If conflict numbers, last one will win
\DIGIT back reference
\w  
\W  
\b  
\B  

3.1.4 Syntax code

\sCODE can be used to refer to any character "whose syntax is CODE". \SCODE is the negative form. See the "Syntax Class Table" chapter of elisp manual for details.

symbol description
\s- whitespace
\s[space] whitespace
\sw \w
\s. punctuation

3.2 constructing

regexp-quote string
return a regular expression, whose only exact match is string. (regexp-quote "^The cat$") returns "\\^The cat\\$". It is useful for example:
(re-search-forward
 (concat "\\s-" (regexp-quote string) "\\s-"))
regexp-opt strings
return an efficient regular expression, that will matches any of the strings supplied.

3.3 Searching

re-search-forward regexp
re-search-backward regexp
string-match regexp string
returns the index of the start of the first match. It will set the Match Data
string-match-p regexp string
same as string-match except it does not modify Match Data.

accessing the match data

match-string count
count is the index, with 0 to the the entire match
match-beginning count
return the beginning index of the match
match-end count

replacing

replace-regexp-in-string regexp rep string
return a modified copy. replace all of matches.

4 Type

(eq OBJ1 OBJ2)
Return t if the two args are the same Lisp object. It is faster than equal.
(equal O1 O2)
Return t if two Lisp objects have similar structure and contents. So it does comparison only.
(=)
true if all arguments are equal. Only works for numbers
(string=)
compare two strings

4.1 number

(expt 2 8)
28

4.2 string

make-string count character
make string by duplicating characters
substring string start &optional end
substring
concat &rest sequences
split-string string &optional separators
split-string-default-separators is "[ \f\t\n\r\v]+"

conversion:

number-to-string number
string-to-number string
char-to-string character
string-to-char string
returns the first character in string

case:

downcase string-or-char
upcase string-or-char
capitalize string-to-char

4.3 cons cell

This is a pair of slots, each of them can hold anything. A list is a list of cons cells, in which each cdr is the "address" next list.

A dotted pair notation is a more general syntax of a cons cell. It is written as (A . B). It is more general because the cdr can also hold anything. As an example, (1 2 3) is the same as (1 . (2 . (3 . nil))).

4.4 list

If the CDR of a list’s last cons cell is some value other than ‘nil’, we call the structure a "dotted list", since its printed representation would use dotted pair notation.

4.4.1 construct

cons obj1 obj2
if obj2 is a list, this is called "cons obj1 onto the list"
list &rest OBJECTS
create a list
make-list length obj
make a list of length, in which each cell holds the same object (eq)
append &rest SEQUENCES
concatenate some lists into one list. The last one is usually a list, all arguments except the last one are copied. If want to force copy everything, add a nil as the last of append.
reverse list
reverse the list by copying
number-sequence from to
the list of [from,to], inclusive

4.4.2 access

car
cdr
car-safe
cdr-safe
pop
return the cdr of the list, and also remove it from the list
nth n list
get the nth element, starting from 0
nthcdr n list
execute cdr n times
last list
length
caar
car car, 11
card
car cdr, 12
cdar
cdr car, 21
cddr
cdr cdr, 22

4.4.3 modify

destructive means the cdr of the cons cells are modified.

push element listname
like cons it onto the list, but save it as listname, i.e. modify the variable
add-to-list symbol element
cons element onto the list if it is not there. So the following is equivalent: (add-to-list 'var value) and (or (member value var) (setq var (cons value var)))
setcar cons obj
setcdr cons obj
sort list predicate
this rearrange the cdrs of the list, so, destructive! Examples:
(setq nums '(1 3 2 6 5 4 0))
(sort nums '<) ; accending

4.5 set

We use list as set, by ignoring the order … append to combine two set, then delete-dups to remove duplication …

memq obj list
whether obj is a member of list, using eq
delq obj list
destructively remove all elements eq to obj.
rmq obj list
return a copy of list with all obj removed
member
equal counter-part
member-ignore-case
for string
delete
equal counter-part
remove
equal counter-part
delete-dups
use equal

4.6 association list

This is a special list, each element is a key-value pair.

(setq alist-of-colors
  '((rose . red) (lily . white) (buttercup . yellow)))
assoc KEY aLIST
the first element of LIST whose car equal KEY.
rassoc value alist
compare the cdrs instead of cars
assq KEY aLIST
the first element of LIST whose car eq KEY.
rassq
eq counter-part
copy-alist alist
two-level deep copy
assq-delete-all key alist
delete all elements whose car eq key
rassq-delete-all value alist
cdr counter-part
(assoc-string KEY LIST &optional CASE-FOLD)
assoc for string. if CASE-FOLD is non-nil, case is ignored.

4.7 property list

It is a flat list. The odd elements are property name, and the even elements are values.

(pine cones numbers (1 2 3) color "blue")

It can be structured as

property value
pine cones
numbers (1 2 3)
color "blue"

The property names must be unique. The order of the "pairs" does not matter.

plist-get plist property
plist-put plist property value
lax-plist-get
equal counterpart
lax-plist-put
equal counterpart
plist-member plist property
this is useful because it can distinguish the missing property and the property with value "nil"

4.8 sequence

 _____________________________________________
|                                             |
|          Sequence                           |
|  ______   ________________________________  |
| |      | |                                | |
| | List | |             Array              | |
| |      | |    ________       ________     | |
| |______| |   |        |     |        |    | |
|          |   | Vector |     | String |    | |
|          |   |________|     |________|    | |
|          |  ____________   _____________  | |
|          | |            | |             | | |
|          | | Char-table | | Bool-vector | | |
|          | |____________| |_____________| | |
|          |________________________________| |
|_____________________________________________|
length sequence
elt sequence index
returns the element of SEQUENCE at index
copy-sequence seq
the sequence is new, but the elements are not.

4.9 array

It is fixed length sequence.

4.9.1 constructing

make-vector length object
create vector
vector &rest objects
create vector

4.9.2 accessing

aref array index
getter
aset array index object
setter

4.10 hash table

construct

(make-hash-table)

access

gethash key table
puthash key value table
remhash key table
remove
clrhash table
remove all
maphash function table
call function once for each of the element in table. The function should accept two arguments: key and value

other

hash-table-count table
return number of entries

5 Function

5.1 define

defun name args body ...

5.2 Calling

Usually put the function name as the car of the list will call it. If you want to compute which function to execute at runtime, use funcall: If you want to compute the arguments at runtime, use apply:

funcall function &rest arguments
apply function &rest arguments
same as funcall, but the last of arguments is a list, and will be expanded into many arguments instead of a list.

5.3 Mapping family

mapcar function sequence
execute function on each element of sequence, and return the list of results.
mapc function sequence
same as mapcar except it returns the sequence, with the intention to collect side effect.
mapconcat function sequence separator
execute function on elements of sequence. The results must be strings, and will be concatenated and returned.

5.4 Anonymous functions

It has three forms:

lambda args body...
function function-object
returns the function without evaluating it. It is the "quote" for function
#'
this is the read syntax for the above function special form. You see, it is indeed the "quote" for the function.

5.5 Macro

Macro does not evaluate its arguments. It put the arguments as is and put them into the macro body to form an expression. The expression is then evaluated for result.

defmacro name args body...

6 Control Structure

6.1 Sequential

progn forms...
return the result of final form
prog1 form1 forms...
return the result of form1
prog2 form1 form2 forms...
return the result of form2

6.2 Conditional

if condition then-form else-forms...
when condition then-forms...
unless condition forms...
cond clause...
the clause must be a list: (condition body-forms...). It is not exactly the "case" statement, because the condition is evaluted to true or false. Any remaining forms are ignored.
pcase EXP BRANCH1 BRANCH2 BRANCH3...
this is more like the "case" statement. The EXP is first evaluted and compare with the car of each branches. The branch must be of the form (UPATTERN BODY-FORMS...).

6.2.1 logical computation

  • not
  • and
  • or

6.3 Loop

while condition forms...
dolist (var list [result]) body...
execute body for each element of list, with the bound of var to the current element and result for return.
dotimes (var count [result]) body...
execute body for each index of [0,count), with var bound to the index, and result bound for return.

7 Packages

7.1 Dash.el

https://github.com/magnars/dash.el

This is a collection of list libraries.

  • -map takes a function to map over the list, the anaphoric form with double dashes executed with it exposed as the list item.

    ;; normal version
    (-map (lambda (n) (* n n)) '(1 2 3 4))
    ;; also works for defun, of course
    (defun square (n) (* n n))
    (-map 'square '(1 2 3 4))
    ;; anaphoric version
    (--map (* it it) '(1 2 3 4))
    
  • -update-at: (-update-at N FUNC LIST) Return a list with element at Nth position in LIST replaced with `(func (nth n list))`.
  • -flatten: (-flatten L): Take a nested list L and return its contents as a single, flat list.

7.2 s.el

https://github.com/magnars/s.el

The string manipulation library

7.3 cl-lib.el loop

This package ports many common lisp facilities into elisp, most importantly, the loop facility. So this section, at least for now, focus on cl-loop.

7.3.1 general loop form

(cl-loop clauses...)

The clauses can be:

  • for clauses
  • TODO

7.3.2 for clauses

for VAR from FROM to TO by STEP
  • FROM defaults to 0. STEP must be positive and default to 1.
  • inclusive [from,to]
  • from can be upfrom and downfrom. I think it is wired to use this.
  • to can be upto and downto. This makes more sense.
  • above and below can be used, but exclusive. e.g. for var below 10
for VAR in LIST by FUNCTION
FUNCTION is used to traverse the list, defaults to cdr
for VAR on LIST by FUNCTION
VAR is bound to the cons cell of the list instead of the element.
for VAR across ARRAY
iterates all elements of array
for VAR = EXPR1 then EXPR2
this is the most general form. The VAR is bound to EXPR1 initially, and will be set by evaluating EXPR2 in successive iterations. EXPR2 can refer the old VAR

7.3.3 iteration clauses

repeat integer
repeat the loop how many times
while condition
stops the loop when the condition becomes nil
until condition
always condition
like while except it returns nil, and finally clauses are not executed.
never condition
counter part for always

7.3.4 accumulation clauses

collect form
collect into a list and return the list in the end
append form
collect the lists into a list by appending, and return it in the end
concat form
for string only
count form
count how many times form evaluates to non-nil.
sum form
sum all the values
maximize form
get the max. If the form is never executed, result is undefined
minimize form

7.3.5 Other clauses

with var = value
set the value one-time at the beginning of the loop. Often used as return variable. The spaces around = is essential!.
if condition clause [else clause]
when condition clause
same as if
unless condition clause
similar
initially [do] forms...
execute before the loop begins, but after the for and with variable bindings. do is optional.
finally [do] forms...
execute after the loop finishes
finally return form
finally return it …
do forms...
execute as an implicit progn in the body
return form
this is often used in if or unless, because put it in top level will cause the loop always execute only once.

7.4 cl-lib other

Of course, cl-lib provides much more than just loops …

incf PLACE
is i++

8 Debugging

8.1 lisp debugger

The simplest debugger is called lisp debugger. You can turn on the debug-or-error flag, but I found inserting the (debug) command useful. Simply insert (debug) where you want program to suspend, and run it. You will enter the debugger at that point. In the debugger buffer, the following commands are available:

c
continue run program
d
step
e
evaluate an prompt expression
R
like e, but also save the result in *Debugger-record*
q
quit
v
toggle display of local variables ???

8.2 Edebug

For this to work, first you need to instrument the code. You can instrument the defun by C-u C-M-x. Actually this is adding a prefix before eval-defun, which instrument, and then evaluate the defun.

After instrumentation, running the defun will cause the program to stop at the first stop point of the function. The stop points are

  • before and after each subexpression that is a list
  • after each variable reference

8.2.1 breakpoints

b
set a breakpoint
u
unset a breakpoint
x CONDITION
set a conditional breakpoint

You can also set the source breakpoints, by adding (edebug).

8.2.2 Moving of point

B
move point to the next breakpoint
w
move point back to the current stop point

8.2.3 executions

<SPC>
run to next stop point
g
execute until next breakpoint
q
exit
S
stop and wait for Edebug commands
n
evaluate a sexp and stop at stop point
t
trace, pause one second at each stop point …
T
rapid trace. Update the display at each stop point but don't actually pause …
c
pause one second at each breakpoint
C
rapid continue.
G
run and ignore breakpoints (but you can stop it by S)
h
proceed to the stop point near the point …
f
run one expression
o
step out the containing expression
i
step in

8.2.4 evaluation

e EXP
evaluate a prompt expression
C-x C-e
evaluate an expression at point

8.2.5 other commands

?
show help
r
redisplay the most recent sexp result
d
display the backtrace

9 Unit Testing

Use ert for unit testing.

9.1 Write test

(ert-deftest addition-test()
  "Outline docstring."
  (should (= (+ 1 2) 4)))

The family of functions:

  • should
  • shoult-not
  • should-error

expected failure:

(ert-deftest addition-test()
  "Outline docstring."
  :expected-result :failed
  (should (= (+ 1 2) 4)))

skip test

(ert-deftest addition-test()
  "Outline docstring."
  (slip-unless (featurep 'dbusbind'))
  (should (= (+ 1 2) 4)))

9.2 Run test

M-x ert will run it. The selector of test accept some more fancy staff like regular expression matching. But in the case of scratch testing, I need to evaluate the deftest and then call ert.

The nice thing is it supports interactive debugging. In the ert buffer, the following commands are available:

r
re-run the test
.
jump to the source code of this test
b
show back-trace
m
show the message this test printed
d
re-run the test with debugger enabled
instrumentation
go to source code, type C-u C-M-x, and re-run the test. You are able to step!

Also, select test by this:

(ert-run-test (ert-get-test 'my-defined-test))

10 Some random code snippets

(cl-prettyprint (font-family-list)) ;; see all font family available on this system

10.0.1 Url retrieval

(with-current-buffer (url-retrieve-synchronously "http://scholar.google.com/scholar?q=segmented symbolic analysis")
  (goto-char (point-min))
  (kill-ring-save (point-min) (point-max))
  )
(let ((framed-url (match-string 1)))
  (with-current-buffer (url-retrieve-synchronously framed-url)
    (goto-char (point-min))
    (when (re-search-forward "<frame src=\"\\(http[[:ascii:]]*?\\)\"")
      (match-string 1))))

Author: Hebi Li

Created: 2017-03-27 Mon 14:36

Validate