Professional Documents
Culture Documents
tion to
Programming in Ema
s Lisp
An Introdu
tion to
Programming in Ema
s Lisp
Se
ond Edition
by Robert J. Chassell
Copyright
1990, 1991, 1992, 1993, 1994, 1995, 1997, 2001, 2002 Free
Software Foundation, In
.
Short Contents
Prefa
e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
1 List Pro
essing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2 Pra
ti
ing Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3 How To Write Fun
tion Denitions . . . . . . . . . . . . . . . . . . 29
4 A Few Buer{Related Fun
tions . . . . . . . . . . . . . . . . . . . . 51
5 A Few More Complex Fun
tions . . . . . . . . . . . . . . . . . . . . 63
6 Narrowing and Widening . . . . . . . . . . . . . . . . . . . . . . . . . 77
7
ar,
dr,
ons: Fundamental Fun
tions . . . . . . . . . . . . . 81
8 Cutting and Storing Text . . . . . . . . . . . . . . . . . . . . . . . . . 89
9 How Lists are Implemented . . . . . . . . . . . . . . . . . . . . . . . 113
10 Yanking Text Ba
k . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
11 Loops and Re
ursion . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
12 Regular Expression Sear
hes . . . . . . . . . . . . . . . . . . . . . . 149
13 Counting: Repetition and Regexps . . . . . . . . . . . . . . . . . . 167
14 Counting Words in a defun . . . . . . . . . . . . . . . . . . . . . . 181
15 Readying a Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
16 Your `.ema
s' File . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
17 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
18 Con
lusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Appendix A The the-the Fun
tion . . . . . . . . . . . . . . . . . . 241
Appendix B Handling the Kill Ring . . . . . . . . . . . . . . . . . . . 243
Appendix C A Graph with Labelled Axes . . . . . . . . . . . . . . . 255
Appendix D GNU Free Do
umentation Li
ense . . . . . . . . . . . 279
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
ii
iii
Table of Contents
Prefa
e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
On Reading this Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
For Whom This is Written . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii
Lisp History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
A Note for Novi
es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Thank You . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv
17 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
17.1 231
debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17.2 debug-on-entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .232
17.3 debug-on-quit and (debug) . . . . . . . . . . . . . . . . . . . . . . . . . . 234
17.4 The edebug Sour
e Level Debugger . . . . . . . . . . . . . . . . . . . . 235
17.5 Debugging Exer
ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
ix
18 Con
lusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Appendix A The the-the Fun
tion . . . . . . . . . . 241
Appendix B Handling the Kill Ring . . . . . . . . 243
B.1 The rotate-yank-pointer Fun
tion . . . . . . . . . . . . . . . . . . . 243
B.1.1 The Body of rotate-yank-pointer .. . . . . . . . . . 244
The else-part of the if expression . . . . . . . . . . . . . 245
The % remainder fun
tion . . . . . . . . . . . . . . . . . . . . . 247
Using % in rotate-yank-pointer . . . . . . . . . . . . . 248
Pointing to the last element . . . . . . . . . . . . . . . . . . . 248
B.2 yank . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
Passing the argument . . . . . . . . . . . . . . . . . . . . . . . . 250
Passing a negative argument . . . . . . . . . . . . . . . . . . 251
B.3 yank-pop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
x
On Reading this Text xi
Prefa
e
Most of the GNU Ema
s integrated environment is written in the pro-
gramming language
alled Ema
s Lisp. The
ode written in this program-
ming language is the software|the sets of instru
tions|that tell the
om-
puter what to do when you give it
ommands. Ema
s is designed so that
you
an write new
ode in Ema
s Lisp and easily install it as an extension
to the editor.
(GNU Ema
s is sometimes
alled an \extensible editor", but it does mu
h
more than provide editing
apabilities. It is better to refer to Ema
s as
an \extensible
omputing environment". However, that phrase is quite a
mouthful. It is easier to refer to Ema
s simply as an editor. Moreover,
everything you do in Ema
s|nd the Mayan date and phases of the moon,
simplify polynomials, debug
ode, manage les, read letters, write books|all
these a
tivities are kinds of editing in the most general sense of the word.)
Although Ema
s Lisp is usually thought of in asso
iation only with
Ema
s, it is a full
omputer programming language. You
an use Ema
s
Lisp as you would any other programming language.
Perhaps you want to understand programming; perhaps you want to ex-
tend Ema
s; or perhaps you want to be
ome a programmer. This introdu
-
tion to Ema
s Lisp is designed to get you started: to guide you in learning
the fundamentals of programming, and more importantly, to show you how
you
an tea
h yourself to go further.
Lisp History
Lisp was rst developed in the late 1950s at the Massa
husetts Institute
of Te
hnology for resear
h in arti
ial intelligen
e. The great power of the
Lisp language makes it superior for other purposes as well, su
h as writing
editor
ommands and integrated environments.
GNU Ema
s Lisp is largely inspired by Ma
lisp, whi
h was written at
MIT in the 1960s. It is somewhat inspired by Common Lisp, whi
h be
ame
a standard in the 1980s. However, Ema
s Lisp is mu
h simpler than Common
Lisp. (The standard Ema
s distribution
ontains an optional extensions le,
`
l.el', that adds many Common Lisp features to Ema
s Lisp.)
In addition to typing a lone key
hord, you
an prex what you type with
C-u, whi
h is
alled the `universal argument'. The C-u key
hord passes an
argument to the subsequent
ommand. Thus, to indent a region of plain
text by 6 spa
es, mark the region, and then type C-u 6 M-C-\. (If you do
not spe
ify a number, Ema
s either passes the number 4 to the
ommand
or otherwise runs the
ommand dierently than it would otherwise.) See
se
tion \Numeri
Arguments" in The GNU Ema
s Manual.
If you are reading this in Info using GNU Ema
s, you
an read through
this whole do
ument just by pressing the spa
e bar, hSPCi. (To learn about
Info, type C-h i and then sele
t Info.)
A note on terminology: when I use the word Lisp alone, I often am
referring to the various diale
ts of Lisp in general, but when I speak of
Ema
s Lisp, I am referring to GNU Ema
s Lisp in parti
ular.
Thank You
My thanks to all who helped me with this book. My espe
ial thanks to
Jim Blandy, Noah Friedman, Jim Kingdon, Roland M
Grath, Frank Ritter,
Randy Smith, Ri
hard M. Stallman, and Melissa Weisshaus. My thanks
also go to both Philip Johnson and David Stampe for their patient en
our-
agement. My mistakes are my own.
Robert J. Chassell
Lisp Atoms 1
`+'. On the other hand, unlike an atom, a list
an be split into parts. (See
Chapter 7, \
ar
dr &
ons Fundamental Fun
tions", page 81.)
The printed representation of both atoms and lists are
alled symboli
expressions or, more
on
isely, s-expressions. The word expression by itself
an refer to either the printed representation, or to the atom or list as it
is held internally in the
omputer. Often, people use the term expression
indis
riminately. (Also, in many texts, the word form is used as a synonym
for expression.)
In
identally, the atoms that make up our universe were named su
h when
they were thought to be indivisible; but it has been found that physi
al atoms
are not indivisible. Parts
an split o an atom or it
an ssion into two parts
of roughly equal size. Physi
al atoms were named prematurely, before their
truer nature was found. In Lisp,
ertain kinds of atom, su
h as an array,
an
be separated into parts; but the me
hanism for doing this is dierent from
the me
hanism for splitting a list. As far as list operations are
on
erned,
the atoms of a list are unsplittable.
There are many kinds of atom in nature but only a few in Lisp: for
example, numbers, su
h as 37, 511, or 1729, and symbols, su
h as `+', `foo',
or `forward-line'. The words we have listed in the examples above are
all symbols. In everyday Lisp
onversation, the word \atom" is not often
used, be
ause programmers usually try to be more spe
i
about what kind
of atom they are dealing with. Lisp programming is mostly about symbols
(and sometimes numbers) within lists. (In
identally, the pre
eding three
word parentheti
al remark is a proper list in Lisp, sin
e it
onsists of atoms,
whi
h in this
ase are symbols, separated by whitespa
e and en
losed by
parentheses, without any non-Lisp pun
tuation.)
GNU Ema
s Helps You Type Lists 3
its
losing parenthesis mat
h its opening parenthesis. (See se
tion \Major
Modes" in The GNU Ema
s Manual, for more information about Ema
s'
modes.)
harmless a
tivity; and indeed, we will often try to generate error messages
intentionally. On
e you understand the jargon, error messages
an be in-
formative. Instead of being
alled \error" messages, they should be
alled
\help" messages. They are like signposts to a traveller in a strange
ountry;
de
iphering them
an be hard, but on
e understood, they
an point the way.
The error message is generated by a built-in GNU Ema
s debugger. We
will `enter the debugger'. You get out of the debugger by typing q.
What we will do is evaluate a list that is not quoted and does not have
a meaningful
ommand as its rst element. Here is a list almost exa
tly the
same as the one we just used, but without the single-quote in front of it.
Position the
ursor right after it and type C-x C-e:
(this is an unquoted list)
What you see depends on whi
h version of Ema
s you are running. GNU
Ema
s version 21 provides more information than version 20 and before.
First, the more re
ent result of generating an error; then the earlier, version
20 result.
In GNU Ema
s version 21, a `*Ba
ktra
e*' window will open up and you
will see the following in it:
---------- Buffer: *Ba
ktra
e* ----------
Debugger entered--Lisp error: (void-fun
tion this)
(this is an unquoted list)
eval((this is an unquoted list))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
all-intera
tively(eval-last-sexp)
---------- Buffer: *Ba
ktra
e* ----------
Your
ursor will be in this window (you may have to wait a few se
onds
before it be
omes visible). To quit the debugger and make the debugger
window go away, type:
q
Please type q right now, so you be
ome
ondent that you
an get out of
the debugger. Then, type C-x C-e again to re-enter it.
Based on what we already know, we
an almost read this error message.
You read the `*Ba
ktra
e*' buer from the bottom up; it tells you what
Ema
s did. When you typed C-x C-e, you made an intera
tive
all to the
ommand eval-last-sexp. eval is an abbreviation for `evaluate' and sexp
is an abbreviation for `symboli
expression'. The
ommand means `evaluate
last symboli
expression', whi
h is the expression just before your
ursor.
Ea
h line above tells you what the Lisp interpreter evaluated next. The
most re
ent a
tion is at the top. The buer is
alled the `*Ba
ktra
e*'
buer be
ause it enables you to tra
k Ema
s ba
kwards.
6 Chapter 1: List Pro
essing
At the top of the `*Ba
ktra
e*' buer, you see the line:
Debugger entered--Lisp error: (void-fun
tion this)
The Lisp interpreter tried to evaluate the rst atom of the list, the word
`this'. It is this a
tion that generated the error message `void-fun
tion
this'.
The message
ontains the words `void-fun
tion' and `this'.
The word `fun
tion' was mentioned on
e before. It is a very important
word. For our purposes, we
an dene it by saying that a fun
tion is a set
of instru
tions to the
omputer that tell the
omputer to do something.
Now we
an begin to understand the error message: `void-fun
tion
this'. The fun
tion (that is, the word `this') does not have a denition of
any set of instru
tions for the
omputer to
arry out.
The slightly odd word, `void-fun
tion', is designed to
over the way
Ema
s Lisp is implemented, whi
h is that when a symbol does not have a
fun
tion denition atta
hed to it, the pla
e that should
ontain the instru
-
tions is `void'.
On the other hand, sin
e we were able to add 2 plus 2 su
essfully, by
evaluating (+ 2 2), we
an infer that the symbol + must have a set of in-
stru
tions for the
omputer to obey and those instru
tions must be to add
the numbers that follow the +.
In GNU Ema
s version 20, and in earlier versions, you will see only one
line of error message; it will appear in the e
ho area and look like this:
Symbol's fun
tion definition is void: this
(Also, your terminal may beep at you|some do, some don't; and others
blink. This is just a devi
e to get your attention.) The message goes away
as soon as you type another key, even just to move the
ursor.
We know the meaning of the word `Symbol'. It refers to the rst atom of
the list, the word `this'. The word `fun
tion' refers to the instru
tions that
tell the
omputer what to do. (Te
hni
ally, the symbol tells the
omputer
where to nd the instru
tions, but this is a
ompli
ation we
an ignore for
the moment.)
The error message
an be understood: `Symbol's fun
tion definition
is void: this'. The symbol (that is, the word `this') la
ks instru
tions for
the
omputer to
arry out.
`Bob'; however, I am not the letters `B', `o', `b' but am the
ons
iousness
onsistently asso
iated with a parti
ular life-form. The name is not me, but
it
an be used to refer to me.
In Lisp, one set of instru
tions
an be atta
hed to several names. For
example, the
omputer instru
tions for adding numbers
an be linked to the
symbol plus as well as to the symbol + (and are in some diale
ts of Lisp).
Among humans, I
an be referred to as `Robert' as well as `Bob' and by
other words as well.
On the other hand, a symbol
an have only one fun
tion denition at-
ta
hed to it at a time. Otherwise, the
omputer would be
onfused as to
whi
h denition to use. If this were the
ase among people, only one person
in the world
ould be named `Bob'. However, the fun
tion denition to whi
h
the name refers
an be
hanged readily. (See Se
tion 3.2, \Install a Fun
tion
Denition", page 31.)
Sin
e Ema
s Lisp is large, it is
ustomary to name symbols in a way that
identies the part of Ema
s to whi
h the fun
tion belongs. Thus, all the
names for fun
tions that deal with Texinfo start with `texinfo-' and those
for fun
tions that deal with reading mail start with `rmail-'.
The third and nal
ompli
ation is this: if the fun
tion that the Lisp
interpreter is looking at is not a spe
ial form, and if it is part of a list, the
Lisp interpreter looks to see whether the list has a list inside of it. If there
is an inner list, the Lisp interpreter rst gures out what it should do with
the inside list, and then it works on the outside list. If there is yet another
list embedded inside the inner list, it works on that one rst, and so on.
It always works on the innermost list rst. The interpreter works on the
innermost list rst, to evaluate the result of that list. The result may be
used by the en
losing expression.
Otherwise, the interpreter works left to right, from one expression to the
next.
1.6 Evaluation
When the Lisp interpreter works on an expression, the term for the a
-
tivity is
alled evaluation. We say that the interpreter `evaluates the expres-
sion'. I've used this term several times before. The word
omes from its
use in everyday language, `to as
ertain the value or amount of; to appraise',
a
ording to Webster's New Collegiate Di
tionary.
After evaluating an expression, the Lisp interpreter will most likely return
the value that the
omputer produ
es by
arrying out the instru
tions it
found in the fun
tion denition, or perhaps it will give up on that fun
tion
and produ
e an error message. (The interpreter may also nd itself tossed,
so to speak, to a dierent fun
tion or it may attempt to repeat
ontinually
what it is doing for ever and ever in what is
alled an `innite loop'. These
a
tions are less
ommon; and we
an ignore them.) Most frequently, the
interpreter returns a value.
Evaluating Inner Lists 9
result of the
omputer
arrying out the instru
tions in the fun
tion denition
atta
hed to that name. If a symbol by itself is evaluated, something dierent
happens, as we will see in the next se
tion.
1.7 Variables
In Ema
s Lisp, a symbol
an have a value atta
hed to it just as it
an
have a fun
tion denition atta
hed to it. The two are dierent. The fun
tion
denition is a set of instru
tions that a
omputer will obey. A value, on the
other hand, is something, su
h as number or a name, that
an vary (whi
h
is why su
h a symbol is
alled a variable). The value of a symbol
an be any
expression in Lisp, su
h as a symbol, number, list, or string. A symbol that
has a value is often
alled a variable.
A symbol
an have both a fun
tion denition and a value atta
hed to it
at the same time. Or it
an have just one or the other. The two are separate.
This is somewhat similar to the way the name Cambridge
an refer to the
ity in Massa
husetts and have some information atta
hed to the name as
well, su
h as \great programming
enter".
Another way to think about this is to imagine a symbol as being a
hest of
drawers. The fun
tion denition is put in one drawer, the value in another,
and so on. What is put in the drawer holding the value
an be
hanged
without ae
ting the
ontents of the drawer holding the fun
tion denition,
and vi
e-versa.
The variable fill-
olumn illustrates a symbol with a value atta
hed to
it: in every GNU Ema
s buer, this symbol is set to some value, usually 72
or 70, but sometimes to some other value. To nd the value of this symbol,
evaluate it by itself. If you are reading this in Info inside of GNU Ema
s,
you
an do this by putting the
ursor after the symbol and typing C-x C-e:
fill-
olumn
After I typed C-x C-e, Ema
s printed the number 72 in my e
ho area. This
is the value for whi
h fill-
olumn is set for me as I write this. It may
be dierent for you in your Info buer. Noti
e that the value returned as
a variable is printed in exa
tly the same way as the value returned by a
fun
tion
arrying out its instru
tions. From the point of view of the Lisp
interpreter, a value returned is a value returned. What kind of expression it
ame from
eases to matter on
e the value is known.
A symbol
an have any value atta
hed to it or, to use the jargon, we
an
bind the variable to a value: to a number, su
h as 72; to a string, "su
h as
this"; to a list, su
h as (spru
e pine oak); we
an even bind a variable to
a fun
tion denition.
A symbol
an be bound to a value in several ways. See Se
tion 1.9,
\Setting the Value of a Variable", page 17, for information about one way
to do this.
Error Message for a Symbol Without a Value 11
This ba
ktra
e is dierent from the very rst error message we saw,
whi
h said, `Debugger entered--Lisp error: (void-fun
tion this)'. In
this
ase, the fun
tion does not have a value as a variable; while in the other
error message, the fun
tion (the word `this') did not have a denition.
In this experiment with the +, what we did was
ause the Lisp interpreter
to evaluate the + and look for the value of the variable instead of the fun
tion
denition. We did this by pla
ing the
ursor right after the symbol rather
than after the parenthesis of the en
losing list as we did before. As a
onse-
quen
e, the Lisp interpreter evaluated the pre
eding s-expression, whi
h in
this
ase was the + by itself.
Sin
e + does not have a value bound to it, just the fun
tion denition,
the error message reported that the symbol's value as a variable was void.
In GNU Ema
s version 20 and before, your error message will say:
Symbol's value as variable is void: +
The meaning is the same as in GNU Ema
s 21.
1.8 Arguments
To see how information is passed to fun
tions, let's look again at our old
standby, the addition of two plus two. In Lisp, this is written as follows:
(+ 2 2)
If you evaluate this expression, the number 4 will appear in your e
ho
area. What the Lisp interpreter does is add the numbers that follow the +.
The numbers added by + are
alled the arguments of the fun
tion +.
These numbers are the information that is given to or passed to the fun
tion.
The word `argument'
omes from the way it is used in mathemati
s and
does not refer to a disputation between two people; instead it refers to the
information presented to the fun
tion, in this
ase, to the +. In Lisp, the
arguments to a fun
tion are the atoms or lists that follow the fun
tion. The
values returned by the evaluation of these atoms or lists are passed to the
fun
tion. Dierent fun
tions require dierent numbers of arguments; some
fun
tions require none at all.1
1 It is
urious to tra
k the path by whi
h the word `argument'
ame to have two dier-
ent meanings, one in mathemati
s and the other in everyday English. A
ording to
the Oxford English Di
tionary, the word derives from the Latin for `to make
lear,
prove'; thus it
ame to mean, by one thread of derivation, `the eviden
e oered as
proof', whi
h is to say, `the information oered', whi
h led to its meaning in Lisp.
But in the other thread of derivation, it
ame to mean `to assert in a manner against
whi
h others may make
ounter assertions', whi
h led to the meaning of the word as a
disputation. (Note here that the English word has two dierent denitions atta
hed to
it at the same time. By
ontrast, in Ema
s Lisp, a symbol
annot have two dierent
fun
tion denitions at the same time.)
An Argument as the Value of a Variable or List 13
to the fun
tion
on
at are the strings "The " and " red foxes." and the
list (number-to-string (+ 2 fill-
olumn)).
(
on
at "The " (number-to-string (+ 2 fill-
olumn)) " red foxes.")
If you evaluate this expression|and if, as with my Ema
s, fill-
olumn
evaluates to 72|"The 74 red foxes." will appear in the e
ho area. (Note
that you must put spa
es after the word `The' and before the word `red'
so they will appear in the nal string. The fun
tion number-to-string
onverts the integer that the addition fun
tion returns to a string. number-
to-string is also known as int-to-string.)
(*) ) 1
In this set, the fun
tions have one argument ea
h:
(+ 3) ) 3
(* 3) ) 3
In this set, the fun
tions have three arguments ea
h:
(+ 3 4 5) ) 12
(* 3 4 5) ) 60
In GNU Ema
s version 21, you will
reate and enter a `*Ba
ktra
e*'
buer that says:
---------- Buffer: *Ba
ktra
e* ----------
Debugger entered--Lisp error:
(wrong-type-argument number-or-marker-p hello)
+(2 hello)
eval((+ 2 (quote hello)))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
all-intera
tively(eval-last-sexp)
---------- Buffer: *Ba
ktra
e* ----------
As usual, the error message tries to be helpful and makes sense after you
learn how to read it.
The rst part of the error message is straightforward; it says `wrong type
argument'. Next
omes the mysterious jargon word `number-or-marker-p'.
This word is trying to tell you what kind of argument the + expe
ted.
The symbol number-or-marker-p says that the Lisp interpreter is try-
ing to determine whether the information presented it (the value of the
argument) is a number or a marker (a spe
ial obje
t representing a buer
position). What it does is test to see whether the + is being given numbers to
add. It also tests to see whether the argument is something
alled a marker,
whi
h is a spe
i
feature of Ema
s Lisp. (In Ema
s, lo
ations in a buer
are re
orded as markers. When the mark is set with the C- or C-hSPCi
ommand, its position is kept as a marker. The mark
an be
onsidered a
number|the number of
hara
ters the lo
ation is from the beginning of the
buer.) In Ema
s Lisp, +
an be used to add the numeri
value of marker
positions as numbers.
The `p' of number-or-marker-p is the embodiment of a pra
ti
e started
in the early days of Lisp programming. The `p' stands for `predi
ate'. In the
jargon used by the early Lisp resear
hers, a predi
ate refers to a fun
tion
to determine whether some property is true or false. So the `p' tells us that
number-or-marker-p is the name of a fun
tion that determines whether it
is true or false that the argument supplied is a number or a marker. Other
Lisp symbols that end in `p' in
lude zerop, a fun
tion that tests whether its
argument has the value of zero, and listp, a fun
tion that tests whether its
argument is a list.
Finally, the last part of the error message is the symbol hello. This is the
value of the argument that was passed to +. If the addition had been passed
the
orre
t type of obje
t, the value passed would have been a number, su
h
as 37, rather than a symbol like hello. But then you would not have got
the error message.
16 Chapter 1: List Pro
essing
The list (rose violet daisy butter
up) will appear in the e
ho area. This
is what is returned by the set fun
tion. As a side ee
t, the symbol flowers
is bound to the list ; that is, the symbol flowers, whi
h
an be viewed as a
variable, is given the list as its value. (This pro
ess, by the way, illustrates
how a side ee
t to the Lisp interpreter, setting the value,
an be the primary
ee
t that we humans are interested in. This is be
ause every Lisp fun
tion
must return a value if it does not get an error, but it will only have a side
ee
t if it is designed to have one.)
After evaluating the set expression, you
an evaluate the symbol flowers
and it will return the value you just set. Here is the symbol. Pla
e your
ursor after it and type C-x C-e.
flowers
When you evaluate flowers, the list (rose violet daisy butter
up) ap-
pears in the e
ho area.
In
identally, if you evaluate 'flowers, the variable with a quote in front
of it, what you will see in the e
ho area is the symbol itself, flowers. Here
is the quoted symbol, so you
an try this:
'flowers
Note also, that when you use set, you need to quote both arguments to
set, unless you want them evaluated. Sin
e we do not want either argument
evaluated, neither the variable flowers nor the list (rose violet daisy
butter
up), both are quoted. (When you use set without quoting its rst
argument, the rst argument is evaluated before anything else is done. If
you did this and flowers did not have a value already, you would get an
error message that the `Symbol's value as variable is void'; on the other
hand, if flowers did return a value after it was evaluated, the set would
attempt to set the value that was returned. There are situations where this
is the right thing for the fun
tion to do; but su
h situations are rare.)
1.9.3 Counting
Here is an example that shows how to use setq in a
ounter. You might
use this to
ount how many times a part of your program repeats itself. First
set a variable to zero; then add one to the number ea
h time the program
repeats itself. To do this, you need a variable that serves as a
ounter, and
two expressions: an initial setq expression that sets the
ounter variable to
zero; and a se
ond setq expression that in
rements the
ounter ea
h time it
is evaluated.
(setq
ounter 0) ; Let's
all this the initializer.
order to evaluate this list, it must evaluate the variable
ounter and the
number 1. When it evaluates the variable
ounter, it re
eives its
urrent
value. It passes this value and the number 1 to the + whi
h adds them
together. The sum is then returned as the value of the inner list and passed
to the setq whi
h sets the variable
ounter to this new value. Thus, the
value of the variable,
ounter, is
hanged.
1.10 Summary
Learning Lisp is like
limbing a hill in whi
h the rst part is the steepest.
You have now
limbed the most diÆ
ult part; what remains be
omes easier
as you progress onwards.
In summary,
Lisp programs are made up of expressions, whi
h are lists or single
atoms.
Lists are made up of zero or more atoms or inner lists, separated by
whitespa
e and surrounded by parentheses. A list
an be empty.
Atoms are multi-
hara
ter symbols, like forward-paragraph, single
hara
ter symbols like +, strings of
hara
ters between double quota-
tion marks, or numbers.
A number evaluates to itself.
A string between double quotes also evaluates to itself.
When you evaluate a symbol by itself, its value is returned.
When you evaluate a list, the Lisp interpreter looks at the rst symbol
in the list and then at the fun
tion denition bound to that symbol.
Then the instru
tions in the fun
tion denition are
arried out.
A single-quote, ', tells the Lisp interpreter that it should return the
following expression as written, and not evaluate it as it would if the
quote were not there.
Arguments are the information passed to a fun
tion. The arguments to
a fun
tion are
omputed by evaluating the rest of the elements of the
list of whi
h the fun
tion is the rst element.
A fun
tion always returns a value when it is evaluated (unless it gets
an error); in addition, it may also
arry out some a
tion
alled a \side
ee
t". In many
ases, a fun
tion's primary purpose is to
reate a side
ee
t.
2.1 Buer Names
The two fun
tions, buffer-name and buffer-file-name, show the dier-
en
e between a le and a buer. When you evaluate the following expression,
(buffer-name), the name of the buer appears in the e
ho area. When you
evaluate (buffer-file-name), the name of the le to whi
h the buer refers
appears in the e
ho area. Usually, the name returned by (buffer-name) is
the same as the name of the le to whi
h it refers, and the name returned
by (buffer-file-name) is the full path-name of the le.
A le and a buer are two dierent entities. A le is information re
orded
permanently in the
omputer (unless you delete it). A buer, on the other
hand, is information inside of Ema
s that will vanish at the end of the editing
session (or when you kill the buer). Usually, a buer
ontains information
that you have
opied from a le; we say the buer is visiting that le. This
opy is what you work on and modify. Changes to the buer do not
hange
24 Chapter 2: Pra
ti
ing Evaluation
the le, until you save the buer. When you save the buer, the buer is
opied to the le and is thus saved permanently.
If you are reading this in Info inside of GNU Ema
s, you
an evaluate
ea
h of the following expressions by positioning the
ursor after it and typing
C-x C-e.
(buffer-name)
(buffer-file-name)
When I do this, `"introdu
tion.texinfo"' is the value returned by eval-
uating (buffer-name), and `"/gnu/work/intro/introdu
tion.texinfo"'
is the value returned by evaluating (buffer-file-name). The former is the
name of the buer and the latter is the name of the le. (In the expres-
sions, the parentheses tell the Lisp interpreter to treat buffer-name and
buffer-file-name as fun
tions; without the parentheses, the interpreter
would attempt to evaluate the symbols as variables. See Se
tion 1.7, \Vari-
ables", page 10.)
In spite of the distin
tion between les and buers, you will often nd
that people refer to a le when they mean a buer and vi
e-versa. Indeed,
most people say, \I am editing a le," rather than saying, \I am editing a
buer whi
h I will soon save to a le." It is almost always
lear from
ontext
what people mean. When dealing with
omputer programs, however, it is
important to keep the distin
tion in mind, sin
e the
omputer is not as smart
as a person.
The word `buer', by the way,
omes from the meaning of the word as
a
ushion that deadens the for
e of a
ollision. In early
omputers, a buer
ushioned the intera
tion between les and the
omputer's
entral pro
essing
unit. The drums or tapes that held a le and the
entral pro
essing unit
were pie
es of equipment that were very dierent from ea
h other, working
at their own speeds, in spurts. The buer made it possible for them to work
together ee
tively. Eventually, the buer grew from being an intermediary,
a temporary holding pla
e, to being the pla
e where work is done. This
transformation is rather like that of a small seaport that grew into a great
ity: on
e it was merely the pla
e where
argo was warehoused temporarily
before being loaded onto ships; then it be
ame a business and
ultural
enter
in its own right.
Not all buers are asso
iated with les. For example, when you start
an Ema
s session by typing the
ommand ema
s alone, without naming any
les, Ema
s will start with the `*s
rat
h*' buer on the s
reen. This buer
is not visiting any le. Similarly, a `*Help*' buer is not asso
iated with
any le.
If you swit
h to the `*s
rat
h*' buer, type (buffer-name), position
the
ursor after it, and type C-x C-e to evaluate the expression, the name
"*s
rat
h*" is returned and will appear in the e
ho area. "*s
rat
h*"
is the name of the buer. However, if you type (buffer-file-name) in
Getting Buers 25
the `*s
rat
h*' buer and evaluate that, nil will appear in the e
ho area.
nil is from the Latin word for `nothing'; in this
ase, it means that the
`*s
rat
h*' buer is not asso
iated with any le. (In Lisp, nil is also used
to mean `false' and is a synonym for the empty list, ().)
In
identally, if you are in the `*s
rat
h*' buer and want the value
returned by an expression to appear in the `*s
rat
h*' buer itself rather
than in the e
ho area, type C-u C-x C-e instead of C-x C-e. This
auses the
value returned to appear after the expression. The buer will look like this:
(buffer-name)"*s
rat
h*"
You
annot do this in Info sin
e Info is read-only and it will not allow you
to
hange the
ontents of the buer. But you
an do this in any buer you
an edit; and when you write
ode or do
umentation (su
h as this book),
this feature is very useful.
swit
hed ba
k and forth from the `*s
rat
h*' buer, other-buffer will
return that buer.
You
an see this by evaluating the expression:
(other-buffer)
You should see `#<buffer *s
rat
h*>' appear in the e
ho area, or the name
of whatever other buer you swit
hed ba
k from most re
ently1 .
The value of point depends, of
ourse, on its lo
ation within the buer.
If you evaluate point in this spot, the number will be larger:
(point)
For me, the value of point in this lo
ation is 66043, whi
h means that there
are 319
hara
ters (in
luding spa
es) between the two expressions.
The fun
tion point-min is somewhat similar to point, but it returns the
value of the minimum permissible value of point in the
urrent buer. This
is the number 1 unless narrowing is in ee
t. (Narrowing is a me
hanism
whereby you
an restri
t yourself, or a program, to operations on just a part
of a buer. See Chapter 6, \Narrowing and Widening", page 77.) Likewise,
the fun
tion point-max returns the value of the maximum permissible value
of point in the
urrent buer.
3. Do
umentation des
ribing the fun
tion. (Te
hni
ally optional, but
strongly re
ommended.)
4. Optionally, an expression to make the fun
tion intera
tive so you
an
use it by typing M-x and then the name of the fun
tion; or by typing an
appropriate key or key
hord.
5. The
ode that instru
ts the
omputer what to do: the body of the
fun
tion denition.
It is helpful to think of the ve parts of a fun
tion denition as being
organized in a template, with slots for ea
h part:
(defun fun
tion-name (arguments ...)
"optional-do
umentation..."
(intera
tive argument-passing-info ) ; optional
body ...)
As an example, here is the
ode for a fun
tion that multiplies its argument
by 7. (This example is not intera
tive. See Se
tion 3.3, \Making a Fun
tion
Intera
tive", page 33, for that information.)
(defun multiply-by-seven (number)
"Multiply NUMBER by seven."
(* 7 number))
This denition begins with a parenthesis and the symbol defun, followed
by the name of the fun
tion.
The name of the fun
tion is followed by a list that
ontains the arguments
that will be passed to the fun
tion. This list is
alled the argument list. In
this example, the list has only one element, the symbol, number. When the
fun
tion is used, the symbol will be bound to the value that is used as the
argument to the fun
tion.
Instead of
hoosing the word number for the name of the argument, I
ould have pi
ked any other name. For example, I
ould have
hosen the
word multipli
and. I pi
ked the word `number' be
ause it tells what kind
of value is intended for this slot; but I
ould just as well have
hosen the
word `multipli
and' to indi
ate the role that the value pla
ed in this slot
will play in the workings of the fun
tion. I
ould have
alled it foogle, but
that would have been a bad
hoi
e be
ause it would not tell humans what it
means. The
hoi
e of name is up to the programmer and should be
hosen
to make the meaning of the fun
tion
lear.
Indeed, you
an
hoose any name you wish for a symbol in an argument
list, even the name of a symbol used in some other fun
tion: the name
you use in an argument list is private to that parti
ular denition. In that
denition, the name refers to a dierent entity than any use of the same name
outside the fun
tion denition. Suppose you have a ni
k-name `Shorty' in
your family; when your family members refer to `Shorty', they mean you.
But outside your family, in a movie, for example, the name `Shorty' refers to
someone else. Be
ause a name in an argument list is private to the fun
tion
Install a Fun
tion Denition 31
the value it returns is the name of the dened fun
tion.) At the same time,
this a
tion installs the fun
tion denition.
(defun multiply-by-seven (number)
"Multiply NUMBER by seven."
(* 7 number))
By evaluating this defun, you have just installed multiply-by-seven in
Ema
s. The fun
tion is now just as mu
h a part of Ema
s as forward-
word or any other editing fun
tion you use. (multiply-by-seven will stay
installed until you quit Ema
s. To reload
ode automati
ally whenever you
start Ema
s, see Se
tion 3.5, \Installing Code Permanently", page 36.)
You
an see the ee
t of installing multiply-by-seven by evaluating the
following sample. Pla
e the
ursor after the following expression and type
C-x C-e. The number 21 will appear in the e
ho area.
(multiply-by-seven 3)
If you wish, you
an read the do
umentation for the fun
tion by typing
C-h f (des
ribe-fun
tion) and then the name of the fun
tion, multiply-
by-seven. When you do this, a `*Help*' window will appear on your s
reen
that says:
multiply-by-seven:
Multiply NUMBER by seven.
(To return to a single window on your s
reen, type C-x 1.)
(See Se
tion 16.7, \Some Keybindings", page 220, to learn how to bind
a
ommand to a key.)
A prex argument is passed to an intera
tive fun
tion by typing the
hMETAi key followed by a number, for example, M-3 M-e, or by typing C-
u and then a number, for example, C-u 3 M-e (if you type C-u without a
number, it defaults to 4).
appears in the e
ho area when you evaluate an expression whose rst element
is message; but when embedded in a fun
tion, message prints the text as a
side ee
t without quotes.)
If a fun
tion does not have arguments, then intera
tive does not require
any. Su
h a fun
tion
ontains the simple expression (intera
tive). The
mark-whole-buffer fun
tion is like this.
Alternatively, if the spe
ial letter-
odes are not right for your appli
ation,
you
an pass your own arguments to intera
tive as a list. See se
tion
\Using Intera
tive" in The GNU Ema
s Lisp Referen
e Manual, for more
information about this advan
ed te
hnique.
3.6 let
The let expression is a spe
ial form in Lisp that you will need to use in
most fun
tion denitions.
The Parts of a let Expression 37
The symbols in the varlist are the variables that are given initial values by
the let spe
ial form. Symbols by themselves are given the initial value of
nil; and ea
h symbol that is the rst element of a two-element list is bound
to the value that is returned when the Lisp interpreter evaluates the se
ond
element.
Thus, a varlist might look like this: (thread (needles 3)). In this
ase,
in a let expression, Ema
s binds the symbol thread to an initial value of
nil, and binds the symbol needles to an initial value of 3.
When you write a let expression, what you do is put the appropriate
expressions in the slots of the let expression template.
If the varlist is
omposed of two-element lists, as is often the
ase, the
template for the let expression looks like this:
(let ((variable value )
(variable value )
...)
body ...)
You may evaluate the example in the usual fashion, by pla
ing the
ur-
sor after the last parenthesis and typing C-x C-e. When you do this, the
following will appear in the e
ho area:
"One kind of animal has stripes and another is fier
e."
As we have seen before, the message fun
tion prints its rst argument,
ex
ept for `%s'. In this example, the value of the variable zebra is printed
at the lo
ation of the rst `%s' and the value of the variable tiger is printed
at the lo
ation of the se
ond `%s'.
The basi
idea behind an if, is that \if a test is true, then an expression
is evaluated." If the test is not true, the expression is not evaluated. For
example, you might make a de
ision su
h as, \if it is warm and sunny, then
go to the bea
h!"
An if expression written in Lisp does not use the word `then'; the test
and the a
tion are the se
ond and third elements of the list whose rst
element is if. Nonetheless, the test part of an if expression is often
alled
the if-part and the se
ond argument is often
alled the then-part.
Also, when an if expression is written, the true-or-false-test is usually
written on the same line as the symbol if, but the a
tion to
arry out if the
test is true, the \then-part", is written on the se
ond and subsequent lines.
This makes the if expression easier to read.
(if true-or-false-test
a
tion-to-
arry-out-if-test-is-true )
The true-or-false-test will be an expression that is evaluated by the Lisp
interpreter.
Here is an example that you
an evaluate in the usual manner. The test is
whether the number 5 is greater than the number 4. Sin
e it is, the message
`5 is greater than 4!' will be printed.
(if (> 5 4) ; if-part
(message "5 is greater than 4!")) ; then-part
(The fun
tion > tests whether its rst argument is greater than its se
ond
argument and returns true if it is.)
Of
ourse, in a
tual use, the test in an if expression will not be xed
for all time as it is by the expression (> 5 4). Instead, at least one of the
variables used in the test will be bound to a value that is not known ahead
of time. (If the value were known ahead of time, we would not need to run
the test!)
For example, the value may be bound to an argument of a fun
tion de-
nition. In the following fun
tion denition, the
hara
ter of the animal is a
value that is passed to the fun
tion. If the value bound to
hara
teristi
is fier
e, then the message, `It's a tiger!' will be printed; otherwise, nil
will be returned.
(defun type-of-animal (
hara
teristi
)
"Print message in e
ho area depending on CHARACTERISTIC.
If the CHARACTERISTIC is the symbol `fier
e',
then warn of a tiger."
(if (equal
hara
teristi
'fier
e)
(message "It's a tiger!")))
The type-of-animal Fun
tion in Detail 41
If you are reading this inside of GNU Ema
s, you
an evaluate the fun
tion
denition in the usual way to install it in Ema
s, and then you
an evaluate
the following two expressions to see the results:
(type-of-animal 'fier
e)
(type-of-animal 'zebra)
When you evaluate (type-of-animal 'fier
e), you will see the following
message printed in the e
ho area: "It's a tiger!"; and when you evaluate
(type-of-animal 'zebra) you will see nil printed in the e
ho area.
'fier
e and the rst argument is the value of the symbol
hara
teristi
|
in other words, the argument passed to this fun
tion.
In the rst exer
ise of type-of-animal, the argument fier
e is passed to
type-of-animal. Sin
e fier
e is equal to fier
e, the expression, (equal
hara
teristi
'fier
e), returns a value of true. When this happens, the
if evaluates the se
ond argument or then-part of the if: (message "It's
tiger!").
On the other hand, in the se
ond exer
ise of type-of-animal, the argu-
ment zebra is passed to type-of-animal. zebra is not equal to fier
e, so
the then-part is not evaluated and nil is returned by the if expression.
Note that the dierent levels of indentation make it easy to distinguish the
then-part from the else-part. (GNU Ema
s has several
ommands that au-
tomati
ally indent if expressions
orre
tly. See Se
tion 1.1.3, \GNU Ema
s
Helps You Type Lists", page 3.)
We
an extend the type-of-animal fun
tion to in
lude an else-part by
simply in
orporating an additional part to the if expression.
Truth and Falsehood in Ema
s Lisp 43
You
an see the
onsequen
es of doing this if you evaluate the following
version of the type-of-animal fun
tion denition to install it and then
evaluate the two subsequent expressions to pass dierent arguments to the
fun
tion.
(defun type-of-animal (
hara
teristi
) ; Se
ond version.
"Print message in e
ho area depending on CHARACTERISTIC.
If the CHARACTERISTIC is the symbol `fier
e',
then warn of a tiger;
else say it's not fier
e."
(if (equal
hara
teristi
'fier
e)
(message "It's a tiger!")
(message "It's not fier
e!")))
(type-of-animal 'fier e)
(type-of-animal 'zebra)
When you evaluate (type-of-animal 'fier
e), you will see the following
message printed in the e
ho area: "It's a tiger!"; but when you evaluate
(type-of-animal 'zebra), you will see "It's not fier
e!".
(Of
ourse, if the
hara
teristi
were fero
ious, the message "It's not
fier
e!" would be printed; and it would be misleading! When you write
ode, you need to take into a
ount the possibility that some su
h argument
will be tested by the if and write your program a
ordingly.)
The mark is another position in the buer; its value
an be set with a
ommand su
h as C-hSPCi (set-mark-
ommand). If a mark has been set, you
an use the
ommand C-x C-x (ex
hange-point-and-mark) to
ause the
ursor to jump to the mark and set the mark to be the previous position
of point. In addition, if you set another mark, the position of the previous
mark is saved in the mark ring. Many mark positions
an be saved this way.
You
an jump the
ursor to a saved mark by typing C-u C-hSPCi one or more
times.
The part of the buer between point and mark is
alled the region. Nu-
merous
ommands work on the region, in
luding
enter-region,
ount-
lines-region, kill-region, and print-region.
The save-ex
ursion spe
ial form saves the lo
ations of point and mark
and restores those positions after the
ode within the body of the spe
ial form
is evaluated by the Lisp interpreter. Thus, if point were in the beginning
of a pie
e of text and some
ode moved point to the end of the buer, the
save-ex
ursion would put point ba
k to where it was before, after the
expressions in the body of the fun
tion were evaluated.
In Ema
s, a fun
tion frequently moves point as part of its internal work-
ings even though a user would not expe
t this. For example,
ount-lines-
region moves point. To prevent the user from being bothered by jumps that
are both unexpe
ted and (from the user's point of view) unne
essary, save-
ex
ursion is often used to keep point and mark in the lo
ation expe
ted by
the user. The use of save-ex
ursion is good housekeeping.
To make sure the house stays
lean, save-ex
ursion restores the values
of point and mark even if something goes wrong in the
ode inside of it (or,
to be more pre
ise and to use the proper jargon, \in
ase of abnormal exit").
This feature is very helpful.
In addition to re
ording the values of point and mark, save-ex
ursion
keeps tra
k of the
urrent buer, and restores it, too. This means you
an
write
ode that will
hange the buer and have save-ex
ursion swit
h you
ba
k to the original buer. This is how save-ex
ursion is used in append-
to-buffer. (See Se
tion 4.4, \The Denition of append-to-buffer",
page 56.)
3.10.1 Template for a save-ex
ursion Expression
The template for
ode using save-ex
ursion is simple:
(save-ex
ursion
body ...)
The body of the fun
tion is one or more expressions that will be evaluated
in sequen
e by the Lisp interpreter. If there is more than one expression
in the body, the value of the last one will be returned as the value of the
save-ex
ursion fun
tion. The other expressions in the body are evaluated
only for their side ee
ts; and save-ex
ursion itself is used only for its side
ee
t (whi
h is restoring the positions of point and mark).
46 Chapter 3: How To Write Fun
tion Denitions
In more detail, the template for a save-ex
ursion expression looks like
this:
(save-ex
ursion
rst-expression-in-body
se
ond-expression-in-body
third-expression-in-body
...
last-expression-in-body )
An expression, of
ourse, may be a symbol on its own or a list.
In Ema
s Lisp
ode, a save-ex
ursion expression often o
urs within
the body of a let expression. It looks like this:
(let varlist
(save-ex
ursion
body ...))
3.11 Review
In the last few
hapters we have introdu
ed a fair number of fun
tions
and spe
ial forms. Here they are des
ribed in brief, along with a few similar
fun
tions that have not been mentioned yet.
eval-last-sexp
Evaluate the last symboli
expression before the
urrent lo
ation
of point. The value is printed in the e
ho area unless the fun
tion
is invoked with an argument; in that
ase, the output is printed
in the
urrent buer. This
ommand is normally bound to C-x
C-e.
defun Dene fun
tion. This spe
ial form has up to ve parts: the
name, a template for the arguments that will be passed to the
fun
tion, do
umentation, an optional intera
tive de
laration,
and the body of the denition.
For example:
(defun ba
k-to-indentation ()
"Move point to first visible
hara
ter on line."
(intera
tive)
(beginning-of-line 1)
(skip-
hars-forward " \t"))
intera
tive
De
lare to the interpreter that the fun
tion
an be used intera
-
tively. This spe
ial form may be followed by a string with one
or more parts that pass the information to the arguments of the
fun
tion, in sequen
e. These parts may also tell the interpreter
to prompt for information. Parts of the string are separated by
newlines, `\n'.
Review 47
save-ex
ursion
Re
ord the values of point and mark and the
urrent buer
before evaluating the body of this spe
ial form. Restore the
values of point and mark and buer afterward.
For example,
(message "We are %d
hara
ters into this buffer."
(- (point)
(save-ex
ursion
(goto-
har (point-min)) (point))))
For example,
(if (string-equal
(number-to-string 21)
(substring (ema
s-version) 10 12))
(message "This is version 21 Ema
s")
(message "This is not version 21 Ema
s"))
equal
eq Test whether two obje
ts are the same. equal uses one meaning
of the word `same' and eq uses another: equal returns true if
the two obje
ts have a similar stru
ture and
ontents, su
h as
two
opies of the same book. On the other hand, eq, returns
true if both arguments are a
tually the same obje
t.
<
>
<=
>= The < fun
tion tests whether its rst argument is smaller than
its se
ond argument. A
orresponding fun
tion, >, tests whether
the rst argument is greater than the se
ond. Likewise, <= tests
whether the rst argument is less than or equal to the se
ond
and >= tests whether the rst argument is greater than or equal
to the se
ond. In all
ases, both arguments must be numbers or
markers (markers indi
ate positions in buers).
string<
string-lessp
string=
string-equal
The string-lessp fun
tion tests whether its rst argument is
smaller than the se
ond argument. A shorter, alternative name
for the same fun
tion (a defalias) is string<.
The arguments to string-lessp must be strings or symbols;
the ordering is lexi
ographi
, so
ase is signi
ant. The print
names of symbols are used instead of the symbols themselves.
An empty string, `""', a string with no
hara
ters in it, is smaller
than any string of
hara
ters.
string-equal provides the
orresponding test for equality. Its
shorter, alternative name is string=. There are no string test
fun
tions that
orrespond to >, >=, or <=.
message Print a message in the e
ho area. The rst argument is a string
that
an
ontain `%s', `%d', or `%
' to print the value of arguments
that follow the string. The argument used by `%s' must be a
string or a symbol; the argument used by `%d' must be a number.
The argument used by `%
' must be an as
ii
ode number; it will
be printed as the
hara
ter with that as
ii
ode.
Review 49
setq
set The setq fun
tion sets the value of its rst argument to the
value of the se
ond argument. The rst argument is automati-
ally quoted by setq. It does the same for su
eeding pairs of
arguments. Another fun
tion, set, takes only two arguments
and evaluates both of them before setting the value returned by
its rst argument to the value returned by its se
ond argument.
buffer-name
Without an argument, return the name of the buer, as a string.
buffer-file-name
Without an argument, return the name of the le the buer is
visiting.
urrent-buffer
Return the buer in whi
h Ema
s is a
tive; it may not be the
buer that is visible on the s
reen.
other-buffer
Return the most re
ently sele
ted buer (other than the buer
passed to other-buffer as an argument and other than the
urrent buer).
swit
h-to-buffer
Sele
t a buer for Ema
s to be a
tive in and display it in the
urrent window so users
an look at it. Usually bound to C-x b.
set-buffer
Swit
h Ema
s' attention to a buer on whi
h programs will run.
Don't alter what the window is showing.
buffer-size
Return the number of
hara
ters in the
urrent buer.
point Return the value of the
urrent position of the
ursor, as an
integer
ounting the number of
hara
ters from the beginning of
the buer.
point-min
Return the minimum permissible value of point in the
urrent
buer. This is 1, unless narrowing is in ee
t.
point-max
Return the value of the maximum permissible value of point in
the
urrent buer. This is the end of the buer, unless narrowing
is in ee
t.
50 Chapter 3: How To Write Fun
tion Denitions
or `/usr/lo
al/sr
/ema
s/lisp/TAGS'. If the tags table has not already
been
reated, you will have to
reate it yourself.
To
reate a `TAGS' le in a spe
i
dire
tory, swit
h to that dire
tory
in Ema
s using M-x
d
ommand, or list the dire
tory with C-x d (dired).
Then run the
ompile
ommand, with etags *.el as the
ommand to exe-
ute
M-x
ompile RET etags *.el RET
For more information, see Se
tion 12.5, \Create Your Own `TAGS' File",
page 163.
After you be
ome more familiar with Ema
s Lisp, you will nd that you
will frequently use find-tags to navigate your way around sour
e
ode; and
you will
reate your own `TAGS' tables.
In
identally, the les that
ontain Lisp
ode are
onventionally
alled
libraries. The metaphor is derived from that of a spe
ialized library, su
h as
a law library or an engineering library, rather than a general library. Ea
h
library, or le,
ontains fun
tions that relate to a parti
ular topi
or a
tivity,
su
h as `abbrev.el' for handling abbreviations and other typing short
uts,
and `help.el' for on-line help. (Sometimes several libraries provide
ode
for a single a
tivity, as the various `rmail...' les provide
ode for reading
ele
troni
mail.) In The GNU Ema
s Manual, you will see senten
es su
h as
\The C-h p
ommand lets you sear
h the standard Ema
s Lisp libraries by
topi
keywords."
Here is the
omplete text of the shortened version of the fun
tion:
(defun simplified-beginning-of-buffer ()
"Move point to the beginning of the buffer;
leave mark at previous position."
(intera
tive)
(push-mark)
(goto-
har (point-min)))
Like all fun
tion denitions, this denition has ve parts following the
spe
ial form defun:
1. The name: in this example, simplified-beginning-of-buffer.
2. A list of the arguments: in this example, an empty list, (),
3. The do
umentation string.
4. The intera
tive expression.
5. The body.
In this fun
tion denition, the argument list is empty; this means that this
fun
tion does not require any arguments. (When we look at the denition
for the
omplete fun
tion, we will see that it may be passed an optional
argument.)
The intera
tive expression tells Ema
s that the fun
tion is intended to be
used intera
tively. In this example, intera
tive does not have an argument
be
ause simplified-beginning-of-buffer does not require one.
The body of the fun
tion
onsists of the two lines:
(push-mark)
(goto-
har (point-min))
The rst of these lines is the expression, (push-mark). When this ex-
pression is evaluated by the Lisp interpreter, it sets a mark at the
urrent
position of the
ursor, wherever that may be. The position of this mark is
saved in the mark ring.
The next line is (goto-
har (point-min)). This expression jumps the
ursor to the minimum point in the buer, that is, to the beginning of the
buer (or to the beginning of the a
essible portion of the buer if it is
narrowed. See Chapter 6, \Narrowing and Widening", page 77.)
The push-mark
ommand sets a mark at the pla
e where the
ursor was
lo
ated before it was moved to the beginning of the buer by the (goto-
har (point-min)) expression. Consequently, you
an, if you wish, go ba
k
to where you were originally by typing C-x C-x.
That is all there is to the fun
tion denition!
When you are reading
ode su
h as this and
ome upon an unfamiliar
fun
tion, su
h as goto-
har, you
an nd out what it does by using the
des
ribe-fun
tion
ommand. To use this
ommand, type C-h f and then
type in the name of the fun
tion and press hRETi. The des
ribe-fun
tion
54 Chapter 4: A Few Buer{Related Fun
tions
ommand will print the fun
tion's do
umentation string in a `*Help*' win-
dow. For example, the do
umentation for goto-
har is:
One arg, a number. Set point to that number.
Beginning of buffer is position (point-min),
end is (point-max).
(The prompt for des
ribe-fun
tion will oer you the symbol under or
pre
eding the
ursor, so you
an save typing by positioning the
ursor right
over or after the fun
tion and then typing C-h f hRETi.)
The end-of-buffer fun
tion denition is written in the same way as
the beginning-of-buffer denition ex
ept that the body of the fun
tion
ontains the expression (goto-
har (point-max)) in pla
e of (goto-
har
(point-min)).
In this part of the let expression, the one variable, oldbuf, is bound to the
value returned by the (
urrent-buffer) expression. The variable, oldbuf,
is used to keep tra
k of the buer in whi
h you are working and from whi
h
you will
opy.
The element or elements of a varlist are surrounded by a set of parentheses
so the Lisp interpreter
an distinguish the varlist from the body of the let.
As a
onsequen
e, the two-element list within the varlist is surrounded by a
ir
ums
ribing set of parentheses. The line looks like this:
(let ((oldbuf (
urrent-buffer)))
... )
The two parentheses before oldbuf might surprise you if you did not realize
that the rst parenthesis before oldbuf marks the boundary of the varlist
and the se
ond parenthesis marks the beginning of the two-element list,
(oldbuf (
urrent-buffer)).
This formatting
onvention makes it easy to see that the two lines in the
body of the save-ex
ursion are en
losed by the parentheses asso
iated
with save-ex
ursion, just as the save-ex
ursion itself is en
losed by the
parentheses asso
iated with the let:
(let ((oldbuf (
urrent-buffer)))
(save-ex
ursion
(set-buffer (get-buffer-
reate buffer))
(insert-buffer-substring oldbuf start end))))
The use of the save-ex
ursion fun
tion
an be viewed as a pro
ess of
lling in the slots of a template:
(save-ex
ursion
rst-expression-in-body
se
ond-expression-in-body
...
last-expression-in-body )
In this fun
tion, the body of the save-ex
ursion
ontains only two expres-
sions. The body looks like this:
(set-buffer (get-buffer-
reate buffer))
(insert-buffer-substring oldbuf start end)
When the append-to-buffer fun
tion is evaluated, the two expressions
in the body of the save-ex
ursion are evaluated in sequen
e. The value of
the last expression is returned as the value of the save-ex
ursion fun
tion;
the other expression is evaluated only for its side ee
ts.
The rst line in the body of the save-ex
ursion uses the set-buffer
fun
tion to
hange the
urrent buer to the one spe
ied in the rst argument
to append-to-buffer. (Changing the buer is the side ee
t; as we have
said before, in Lisp, a side ee
t is often the primary thing we want.) The
se
ond line does the primary work of the fun
tion.
The set-buffer fun
tion
hanges Ema
s' attention to the buer to whi
h
the text will be
opied and from whi
h save-ex
ursion will return.
The line looks like this:
(set-buffer (get-buffer-
reate buffer))
The innermost expression of this list is (get-buffer-
reate buffer).
This expression uses the get-buffer-
reate fun
tion, whi
h either gets the
named buer, or if it does not exist,
reates one with the given name. This
means you
an use append-to-buffer to put text into a buer that did not
previously exist.
get-buffer-
reate also keeps set-buffer from getting an unne
essary
error: set-buffer needs a buer to go to; if you were to spe
ify a buer that
does not exist, Ema
s would baulk. Sin
e get-buffer-
reate will
reate a
buer if none exists, set-buffer is always provided with a buer.
60 Chapter 4: A Few Buer{Related Fun
tions
The last line of append-to-buffer does the work of appending the text:
(insert-buffer-substring oldbuf start end)
The insert-buffer-substring fun
tion
opies a string from the buer
spe
ied as its rst argument and inserts the string into the present buer.
In this
ase, the argument to insert-buffer-substring is the value of the
variable
reated and bound by the let, namely the value of oldbuf, whi
h
was the
urrent buer when you gave the append-to-buffer
ommand.
After insert-buffer-substring has done its work, save-ex
ursion
will restore the a
tion to the original buer and append-to-buffer will
have done its job.
Written in skeletal form, the workings of the body look like this:
(let (bind-oldbuf-to-value-of-
urrent-buffer)
(save-ex
ursion ; Keep tra
k of buer.
hange-buer
insert-substring-from-oldbuf-into-buer )
4.5 Review
Here is a brief summary of the various fun
tions dis
ussed in this
hapter.
des
ribe-fun
tion
des
ribe-variable
Print the do
umentation for a fun
tion or variable. Convention-
ally bound to C-h f and C-h v.
find-tag Find the le
ontaining the sour
e for a fun
tion or variable and
swit
h buers to it, positioning point at the beginning of the
item. Conventionally bound to M-. (that's a period following
the hMETAi key).
Exer
ises 61
save-ex
ursion
Save the lo
ation of point and mark and restore their values after
the arguments to save-ex
ursion have been evaluated. Also,
remember the
urrent buer and return to it.
push-mark
Set mark at a lo
ation and re
ord the value of the previous mark
on the mark ring. The mark is a lo
ation in the buer that will
keep its relative position even if text is added to or removed
from the buer.
goto-
har
Set point to the lo
ation spe
ied by the value of the argument,
whi
h
an be a number, a marker, or an expression that returns
the number of a position, su
h as (point-min).
insert-buffer-substring
Copy a region of text from a buer that is passed to the fun
tion
as an argument and insert the region into the
urrent buer.
mark-whole-buffer
Mark the whole buer as a region. Normally bound to C-x h.
set-buffer
Swit
h the attention of Ema
s to another buer, but do not
hange the window being displayed. Used when the program
rather than a human is to work on a dierent buer.
get-buffer-
reate
get-buffer
Find a named buer or
reate one if a buer of that name does
not exist. The get-buffer fun
tion returns nil if the named
buer does not exist.
The rst use of save-ex
ursion returns Ema
s to the buer from whi
h
the text is being
opied. That is
lear, and is just like its use in append-
to-buffer. Why the se
ond use? The reason is that insert-buffer-
substring always leaves point at the end of the region being inserted. The
se
ond save-ex
ursion
auses Ema
s to leave point at the beginning of the
text being inserted. In most
ir
umstan
es, users prefer to nd point at the
beginning of inserted text. (Of
ourse, the
opy-to-buffer fun
tion returns
the user to the original buer when done|but if the user then swit
hes to
the
opied-to buer, point will go to the beginning of the text. Thus, this
use of a se
ond save-ex
ursion is a little ni
ety.)
A Read-only Buer
The asterisk is for the situation when the buer is a read-only buer|
a buer that
annot be modied. If insert-buffer is
alled on a buer
that is read-only, a message to this ee
t is printed in the e
ho area and
the terminal may beep or blink at you; you will not be permitted to insert
anything into
urrent buer. The asterisk does not need to be followed by a
newline to separate it from the next argument.
In
identally, using or, the situation with the usher would be written like
this:
(or (holding-on-to-guest) (find-and-take-arm-of-guest))
Like the append-to-buffer fun
tion, the insert-buffer fun
tion uses
let, save-ex
ursion, and set-buffer. In addition, the fun
tion illustrates
one way to use or. All these fun
tions are building blo
ks that we will nd
and use again and again.
5.4 Review
Here is a brief summary of some of the topi
s
overed in this
hapter.
or Evaluate ea
h argument in sequen
e, and return the value of
the rst argument that is not nil; if none return a value that
is not nil, return nil. In brief, return the rst true value of
the arguments; return a true value if one or any of the other are
true.
and Evaluate ea
h argument in sequen
e, and if any are nil, return
nil; if none are nil, return the value of the last argument. In
brief, return a true value only if all the arguments are true;
return a true value if one and ea
h of the others is true.
&optional
A keyword used to indi
ate that an argument to a fun
tion de-
nition is optional; this means that the fun
tion
an be evaluated
without the argument, if desired.
prefix-numeri
-value
Convert the `raw prex argument' produ
ed by (intera
tive
"P") to a numeri
value.
forward-line
Move point forward to the beginning of the next line, or if the
argument is greater than one, forward that many lines. If it
an't move as far forward as it is supposed to, forward-line
goes forward as far as it
an and then returns a
ount of the
number of additional lines it was supposed to move but
ouldn't.
erase-buffer
Delete the entire
ontents of the
urrent buer.
bufferp Return t if its argument is a buer; otherwise return nil.
optional Argument Exer
ise 75
6.2 what-line
The what-line
ommand tells you the number of the line in whi
h the
ursor is lo
ated. The fun
tion illustrates the use of the save-restri
tion
and save-ex
ursion
ommands. Here is the text of the fun
tion in full:
(defun what-line ()
"Print the
urrent line number (in the buffer) of point."
(intera
tive)
(save-restri
tion
(widen)
(save-ex
ursion
(beginning-of-line)
(message "Line %d"
(1+ (
ount-lines 1 (point)))))))
The fun
tion has a do
umentation line and is intera
tive, as you would
expe
t. The next two lines use the fun
tions save-restri
tion and widen.
The save-restri
tion spe
ial form notes whatever narrowing is in ef-
fe
t, if any, in the
urrent buer and restores that narrowing after the
ode
in the body of the save-restri
tion has been evaluated.
Exer
ise with Narrowing 79
The save-restri
tion spe
ial form is followed by widen. This fun
tion
undoes any narrowing the
urrent buer may have had when what-line
was
alled. (The narrowing that was there is the narrowing that save-
restri
tion remembers.) This widening makes it possible for the line
ounting
ommands to
ount from the beginning of the buer. Otherwise,
they would have been limited to
ounting within the a
essible region. Any
original narrowing is restored just before the
ompletion of the fun
tion by
the save-restri
tion spe
ial form.
The
all to widen is followed by save-ex
ursion, whi
h saves the lo
a-
tion of the
ursor (i.e., of point) and of the mark, and restores them after
the
ode in the body of the save-ex
ursion uses the beginning-of-line
fun
tion to move point.
(Note that the (widen) expression
omes between the save-restri
tion
and save-ex
ursion spe
ial forms. When you write the two save- ...
expressions in sequen
e, write save-ex
ursion outermost.)
The last two lines of the what-line fun
tion are fun
tions to
ount the
number of lines in the buer and then print the number in the e
ho area.
(message "Line %d"
(1+ (
ount-lines 1 (point)))))))
The message fun
tion prints a one-line message at the bottom of the
Ema
s s
reen. The rst argument is inside of quotation marks and is printed
as a string of
hara
ters. However, it may
ontain `%d', `%s', or `%
' to print
arguments that follow the string. `%d' prints the argument as a de
imal, so
the message will say something su
h as `Line 243'.
The number that is printed in pla
e of the `%d' is
omputed by the last
line of the fun
tion:
(1+ (
ount-lines 1 (point)))
What this does is
ount the lines from the rst position of the buer, indi-
ated by the 1, up to (point), and then add one to that number. (The 1+
fun
tion adds one to its argument.) We add one to it be
ause line 2 has only
one line before it, and
ount-lines
ounts only the lines before the
urrent
line.
After
ount-lines has done its job, and the message has been printed in
the e
ho area, the save-ex
ursion restores point and mark to their original
positions; and save-restri
tion restores the original narrowing, if any.
In Lisp,
ar,
dr, and
ons are fundamental fun
tions. The
ons fun
tion
is used to
onstru
t lists, and the
ar and
dr fun
tions are used to take
them apart.
In the walk through of the
opy-region-as-kill fun
tion, we will see
ons as well as two variants on
dr, namely, set
dr and nth
dr. (See
Se
tion 8.5, \
opy-region-as-kill", page 102.)
The name of the
ons fun
tion is not unreasonable: it is an abbreviation
of the word `
onstru
t'. The origins of the names for
ar and
dr, on the
other hand, are esoteri
:
ar is an a
ronym from the phrase `Contents of
the Address part of the Register'; and
dr (pronoun
ed `
ould-er') is an
a
ronym from the phrase `Contents of the De
rement part of the Register'.
These phrases refer to spe
i
pie
es of hardware on the very early
omputer
on whi
h the original Lisp was developed. Besides being obsolete, the phrases
have been
ompletely irrelevant for more than 25 years to anyone thinking
about Lisp. Nonetheless, although a few brave s
holars have begun to use
more reasonable names for these fun
tions, the old terms are still in use. In
parti
ular, sin
e the terms are used in the Ema
s Lisp sour
e
ode, we will
use them in this introdu
tion.
7.1
ar and
dr
The
ar of a list is, quite simply, the rst item in the list. Thus the
ar
of the list (rose violet daisy butter
up) is rose.
If you are reading this in Info in GNU Ema
s, you
an see this by evalu-
ating the following:
(
ar '(rose violet daisy butter
up))
After evaluating the expression, rose will appear in the e
ho area.
Clearly, a more reasonable name for the
ar fun
tion would be first
and this is often suggested.
ar does not remove the rst item from the list; it only reports what it
is. After
ar has been applied to a list, the list is still the same as it was. In
the jargon,
ar is `non-destru
tive'. This feature turns out to be important.
The
dr of a list is the rest of the list, that is, the
dr fun
tion returns
the part of the list that follows the rst item. Thus, while the
ar of the
list '(rose violet daisy butter
up) is rose, the rest of the list, the value
returned by the
dr fun
tion, is (violet daisy butter
up).
82 Chapter 7:
ar,
dr,
ons: Fundamental Fun
tions
Also, in the rst
hapter, in the dis
ussion about atoms, I said that in
Lisp, \
ertain kinds of atom, su
h as an array,
an be separated into parts;
but the me
hanism for doing this is dierent from the me
hanism for splitting
a list. As far as Lisp is
on
erned, the atoms of a list are unsplittable."
(See Se
tion 1.1.1, \Lisp Atoms", page 1.) The
ar and
dr fun
tions are
used for splitting lists and are
onsidered fundamental to Lisp. Sin
e they
annot split or gain a
ess to the parts of an array, an array is
onsidered an
atom. Conversely, the other fundamental fun
tion,
ons,
an put together
or
onstru
t a list, but not an array. (Arrays are handled by array-spe
i
fun
tions. See se
tion \Arrays" in The GNU Ema
s Lisp Referen
e Manual.)
7.2
ons
The
ons fun
tion
onstru
ts lists; it is the inverse of
ar and
dr. For
example,
ons
an be used to make a four element list from the three element
list, (fir oak maple):
(
ons 'pine '(fir oak maple))
After evaluating this list, you will see
(pine fir oak maple)
appear in the e
ho area.
ons puts a new element at the beginning of a list;
it atta
hes or pushes elements onto the list.
ons must have a list to atta
h to.1 You
annot start from absolutely
nothing. If you are building a list, you need to provide at least an empty
list at the beginning. Here is a series of
ons expressions that build up a list
of
owers. If you are reading this in Info in GNU Ema
s, you
an evaluate
ea
h of the expressions in the usual way; the value is printed in this text
after `)', whi
h you may read as `evaluates to'.
(
ons 'butter
up ())
) (butter
up)
(
ons 'daisy '(butter
up))
) (daisy butter
up)
(
ons 'violet '(daisy butter
up))
) (violet daisy butter
up)
(
ons 'rose '(violet daisy butter
up))
) (rose violet daisy butter
up)
In the rst example, the empty list is shown as () and a list made up
of butter
up followed by the empty list is
onstru
ted. As you
an see,
the empty list is not shown in the list that was
onstru
ted. All that you
see is (butter
up). The empty list is not
ounted as an element of a list
1 A
tually, you
an
ons an element to an atom to produ
e a dotted pair. Dotted pairs
are not dis
ussed here; see se
tion \Dotted Pair Notation" in The GNU Ema
s Lisp
Referen
e Manual.
84 Chapter 7:
ar,
dr,
ons: Fundamental Fun
tions
7.3 nth
dr
The nth
dr fun
tion is asso
iated with the
dr fun
tion. What it does
is take the
dr of a list repeatedly.
If you take the
dr of the list (pine fir oak maple), you will be returned
the list (fir oak maple). If you repeat this on what was returned, you
will be returned the list (oak maple). (Of
ourse, repeated
dring on the
original list will just give you the original
dr sin
e the fun
tion does not
hange the list. You need to evaluate the
dr of the
dr and so on.) If you
ontinue this, eventually you will be returned an empty list, whi
h in this
ase, instead of being shown as () is shown as nil.
For review, here is a series of repeated
drs, the text following the `)'
shows what is returned.
(
dr '(pine fir oak maple))
)(fir oak maple)
(
dr '(fir oak maple))
) (oak maple)
(
dr '(oak maple))
)(maple)
(
dr '(maple))
) nil
(
dr 'nil)
) nil
(
dr ())
) nil
You
an also do several
drs without printing the values in between, like
this:
(
dr (
dr '(pine fir oak maple)))
) (oak maple)
In this example, the Lisp interpreter evaluates the innermost list rst. The
innermost list is quoted, so it just passes the list as it is to the innermost
dr.
This
dr passes a list made up of the se
ond and subsequent elements of the
list to the outermost
dr, whi
h produ
es a list
omposed of the third and
subsequent elements of the original list. In this example, the
dr fun
tion is
repeated and returns a list that
onsists of the original list without its rst
two elements.
The nth
dr fun
tion does the same as repeating the
all to
dr. In the
following example, the argument 2 is passed to the fun
tion nth
dr, along
with the list, and the value returned is the list without its rst two items,
whi
h is exa
tly the same as repeating
dr twi
e on the list:
(nth
dr 2 '(pine fir oak maple))
) (oak maple)
86 Chapter 7:
ar,
dr,
ons: Fundamental Fun
tions
Using the original four element list, we
an see what happens when various
numeri
arguments are passed to nth
dr, in
luding 0, 1, and 5:
;; Leave the list as it was.
(nth
dr 0 '(pine fir oak maple))
) (pine fir oak maple)
;; Return a
opy without the rst element.
(nth
dr 1 '(pine fir oak maple))
) (fir oak maple)
;; Return a
opy of the list without three elements.
(nth
dr 3 '(pine fir oak maple))
) (maple)
;; Return a
opy la
king all four elements.
(nth
dr 4 '(pine fir oak maple))
) nil
;; Return a
opy la
king all elements.
(nth
dr 5 '(pine fir oak maple))
) nil
7.4 nth
The nth
dr fun
tion takes the
dr of a list repeatedly. The nth fun
tion
takes the
ar of the result returned by nth
dr. It returns the Nth element
of the list.
Thus, if it were not dened in C for speed, the denition of nth would
be:
(defun nth (n list)
"Returns the Nth element of LIST.
N
ounts from zero. If LIST is not that long, nil is returned."
(
ar (nth
dr n list)))
(Originally, nth was dened in Ema
s Lisp in `subr.el', but its denition
was redone in C in the 1980s.)
The nth fun
tion returns a single element of a list. This
an be very
onvenient.
Note that the elements are numbered from zero, not one. That is to
say, the rst element of a list, its
ar is the zeroth element. This is
alled
`zero-based'
ounting and often bothers people who are a
ustomed to the
rst element in a list being number one, whi
h is `one-based'.
set
dr 87
For example:
(nth 0 '("one" "two" "three"))
) "one"
7.5 set
ar
As you might guess from their names, the set
ar and set
dr fun
tions
set the
ar or the
dr of a list to a new value. They a
tually
hange the
original list, unlike
ar and
dr whi
h leave the original list as it was. One
way to nd out how this works is to experiment. We will start with the
set
ar fun
tion.
First, we
an make a list and then set the value of a variable to the list,
using the setq fun
tion. Here is a list of animals:
(setq animals '(antelope giraffe lion tiger))
If you are reading this in Info inside of GNU Ema
s, you
an evaluate this
expression in the usual fashion, by positioning the
ursor after the expression
and typing C-x C-e. (I'm doing this right here as I write this. This is
one of the advantages of having the interpreter built into the
omputing
environment.)
When we evaluate the variable animals, we see that it is bound to the
list (antelope giraffe lion tiger):
animals
) (antelope giraffe lion tiger)
Put another way, the variable animals points to the list (antelope giraffe
lion tiger).
Next, evaluate the fun
tion set
ar while passing it two arguments, the
variable animals and the quoted symbol hippopotamus; this is done by
writing the three element list (set
ar animals 'hippopotamus) and then
evaluating it in the usual fashion:
(set
ar animals 'hippopotamus)
After evaluating this expression, evaluate the variable animals again. You
will see that the list of animals has
hanged:
animals
) (hippopotamus giraffe lion tiger)
The rst element on the list, antelope is repla
ed by hippopotamus.
88 Chapter 7:
ar,
dr,
ons: Fundamental Fun
tions
So we
an see that set
ar did not add a new element to the list as
ons
would have; it repla
ed giraffe with hippopotamus; it
hanged the list.
7.6 set
dr
The set
dr fun
tion is similar to the set
ar fun
tion, ex
ept that the
fun
tion repla
es the se
ond and subsequent elements of a list rather than
the rst element.
To see how this works, set the value of the variable to a list of domesti-
ated animals by evaluating the following expression:
(setq domesti
ated-animals '(horse
ow sheep goat))
If you now evaluate the list, you will be returned the list (horse
ow sheep
goat):
domesti
ated-animals
) (horse
ow sheep goat)
Next, evaluate set
dr with two arguments, the name of the variable
whi
h has a list as its value, and the list to whi
h the
dr of the rst list
will be set;
(set
dr domesti
ated-animals '(
at dog))
If you evaluate this expression, the list (
at dog) will appear in the e
ho
area. This is the value returned by the fun
tion. The result we are inter-
ested in is the \side ee
t", whi
h we
an see by evaluating the variable
domesti
ated-animals:
domesti
ated-animals
) (horse
at dog)
Indeed, the list is
hanged from (horse
ow sheep goat) to (horse
at
dog). The
dr of the list is
hanged from (
ow sheep goat) to (
at dog).
8.2 kill-region
The zap-to-
har fun
tion uses the kill-region fun
tion. This fun
tion
lips text from a region and
opies that text to the kill ring, from whi
h it
may be retrieved.
The Ema
s 21 version of that fun
tion uses
ondition-
ase and
opy-
region-as-kill, both of whi
h we will explain.
ondition-
ase is an
important spe
ial form.
In essen
e, the kill-region fun
tion
alls
ondition-
ase, whi
h takes
three arguments. In this fun
tion, the rst argument does nothing. The
se
ond argument
ontains the
ode that does the work when all goes well.
The third argument
ontains the
ode that is
alled in the event of an error.
We will go through the
ondition-
ase
ode in a moment. First, let us
look at the
omplete denition of kill-region, with
omments added:
(defun kill-region (beg end)
"Kill between point and mark.
The text is deleted but saved in the kill ring."
(intera
tive "r")
;; 1. `
ondition-
ase' takes three arguments.
;; If the first argument is nil, as it is here,
;; information about the error signal is not
;; stored for use by another fun
tion.
(
ondition-
ase nil
;; 2. The se
ond argument to `
ondition-
ase'
;; tells the Lisp interpreter what to do when all goes well.
;; The `delete-and-extra
t-region' fun
tion usually does the
;; work. If the beginning and ending of the region are both
;; the same, then the variable `string' will be empty, or nil
(let ((string (delete-and-extra
t-region beg end)))
;; `when' is an `if'
lause that
annot take an `else-part'.
;; Ema
s normally sets the value of `last-
ommand' to the
;; previous
ommand.
ondition-
ase 95
form. If no error o
urs, the spe
ial form returns the
ode's value and
produ
es the side-ee
ts, if any.
In short, the bodyform part of a
ondition-
ase expression determines
what should happen when everything works
orre
tly.
However, if an error o
urs, among its other a
tions, the fun
tion gener-
ating the error signal will dene one or more error
ondition names.
An error handler is the third argument to
ondition
ase. An error
handler has two parts, a
ondition-name and a body. If the
ondition-name
part of an error handler mat
hes a
ondition name generated by an error,
then the body part of the error handler is run.
As you will expe
t, the
ondition-name part of an error handler may be
either a single
ondition name or a list of
ondition names.
Also, a
omplete
ondition-
ase expression may
ontain more than one
error handler. When an error o
urs, the rst appli
able handler is run.
Lastly, the rst argument to the
ondition-
ase expression, the var
argument, is sometimes bound to a variable that
ontains information about
the error. However, if that argument is nil, as is the
ase in kill-region,
that information is dis
arded.
In brief, in the kill-region fun
tion, the
ode
ondition-
ase works
like this:
If no errors, run only this
ode
but, if errors, run this other
ode.
The sixth part is nearly like the argument that follows the intera
tive
de
laration in a fun
tion written in Lisp: a letter followed, perhaps, by
a prompt. The only dieren
e from the Lisp is when the ma
ro is
alled
with no arguments. Then you write a 0 (whi
h is a `null string'), as in
this ma
ro.
If you were to spe
ify arguments, you would pla
e them between quo-
tation marks. The C ma
ro for goto-
har in
ludes "NGoto
har: " in
this position to indi
ate that the fun
tion expe
ts a raw prex, in this
ase, a numeri
al lo
ation in a buer, and provides a prompt.
The seventh part is a do
umentation string, just like the one for a fun
-
tion written in Ema
s Lisp, ex
ept that every newline must be written
expli
itly as `\n' followed by a ba
kslash and
arriage return.
Thus, the rst two lines of do
umentation for goto-
har are written
like this:
"Set point to POSITION, a number or marker.\n\
Beginning of buffer is position (point-min), end is (point-max).
1 More pre
isely, and requiring more expert knowledge to understand, the two integers
are of type `Lisp Obje
t', whi
h
an also be a C union instead of an integer type.
100 Chapter 8: Cutting and Storing Text
8.5
opy-region-as-kill
The
opy-region-as-kill fun
tion
opies a region of text from a buer
and (via either kill-append or kill-new) saves it in the kill-ring.
If you
all
opy-region-as-kill immediately after a kill-region
om-
mand, Ema
s appends the newly
opied text to the previously
opied text.
This means that if you yank ba
k the text, you get it all, from both this and
the previous operation. On the other hand, if some other
ommand pre
edes
the
opy-region-as-kill, the fun
tion
opies the text into a separate entry
in the kill ring.
Here is the
omplete text of the version 21
opy-region-as-kill fun
-
tion:
(defun
opy-region-as-kill (beg end)
"Save the region as if killed, but don't kill it.
In Transient Mark mode, dea
tivate the mark.
If `interprogram-
ut-fun
tion' is non-nil, also save
the text for a window system
ut and paste."
(intera
tive "r")
(if (eq last-
ommand 'kill-region)
(kill-append (buffer-substring beg end) (< end beg))
(kill-new (buffer-substring beg end)))
(if transient-mark-mode
(setq dea
tivate-mark t))
nil)
As usual, this fun
tion
an be divided into its
omponent parts:
(defun
opy-region-as-kill (argument-list)
"do
umentation..."
(intera
tive "r")
body ...)
The arguments are beg and end and the fun
tion is intera
tive with "r",
so the two arguments must refer to the beginning and end of the region.
If you have been reading though this do
ument from the beginning, under-
standing these parts of a fun
tion is almost be
oming routine.
The do
umentation is somewhat
onfusing unless you remember that the
word `kill' has a meaning dierent from its usual meaning. The `Transient
Mark' and interprogram-
ut-fun
tion
omments explain
ertain side-
ee
ts.
After you on
e set a mark, a buer always
ontains a region. If you
wish, you
an use Transient Mark mode to highlight the region temporarily.
(No one wants to highlight the region all the time, so Transient Mark mode
highlights it only at appropriate times. Many people turn o Transient Mark
mode, so the region is never highlighted.)
The Body of
opy-region-as-kill 103
Also, a windowing system allows you to
opy,
ut, and paste among dier-
ent programs. In the X windowing system, for example, the interprogram-
ut-fun
tion fun
tion is x-sele
t-text, whi
h works with the windowing
system's equivalent of the Ema
s kill ring.
The body of the
opy-region-as-kill fun
tion starts with an if
lause. What this
lause does is distinguish between two dierent situa-
tions: whether or not this
ommand is exe
uted immediately after a previ-
ous kill-region
ommand. In the rst
ase, the new region is appended
to the previously
opied text. Otherwise, it is inserted into the beginning of
the kill ring as a separate pie
e of text from the previous pie
e.
The last two lines of the fun
tion prevent the region from lighting up if
Transient Mark mode is turned on.
The body of
opy-region-as-kill merits dis
ussion in detail.
The if expression reads as follows; it uses eq, whi
h is a fun
tion we have
not yet seen:
(if (eq last-
ommand 'kill-region)
;; then-part
(kill-append (buffer-substring beg end) (< end beg))
;; else-part
(kill-new (buffer-substring beg end)))
The eq fun
tion tests whether its rst argument is the same Lisp obje
t as
its se
ond argument. The eq fun
tion is similar to the equal fun
tion in
that it is used to test for equality, but diers in that it determines whether
two representations are a
tually the same obje
t inside the
omputer, but
with dierent names. equal determines whether the stru
ture and
ontents
of two expressions are the same.
If the previous
ommand was kill-region, then the Ema
s Lisp inter-
preter
alls the kill-append fun
tion
(
on
at (
ar
'("first element" "se
ond element")) " modified")
) "first element modified"
We
an now make sense of kill-append: it modies the
ontents of the
kill ring. The kill ring is a list, ea
h element of whi
h is saved text. The
kill-append fun
tion uses the kill-new fun
tion whi
h in turn uses the
set
ar fun
tion.
This expression rst
onstru
ts a new version of the kill ring by prepending
string to the existing kill ring as a new element. Then it exe
utes a se
ond
if
lause. This se
ond if
lause keeps the kill ring from growing too long.
Let's look at these two expressions in order.
The setq line of the else-part sets the new value of the kill ring to what
results from adding the string being killed to the old kill ring.
We
an see how this works with an example:
(setq example-list '("here is a
lause" "another
lause"))
After evaluating this expression with C-x C-e, you
an evaluate example-
list and see what it returns:
example-list
) ("here is a
lause" "another
lause")
Now, we
an add a new element on to this list by evaluating the following
expression:
(setq example-list (
ons "a third
lause" example-list))
When we evaluate example-list, we nd its value is:
example-list
) ("a third
lause" "here is a
lause" "another
lause")
Thus, the third
lause was added to the list by
ons.
This is exa
tly similar to what the setq and
ons do in the fun
tion.
Here is the line again:
(setq kill-ring (
ons string kill-ring))
Now for the se
ond part of the if
lause. This expression keeps the kill
ring from growing too long. It looks like this:
(if (> (length kill-ring) kill-ring-max)
(set
dr (nth
dr (1- kill-ring-max) kill-ring) nil))
The
ode
he
ks whether the length of the kill ring is greater than the
maximum permitted length. This is the value of kill-ring-max (whi
h is
60, by default). If the length of the kill ring is too long, then this
ode sets
the last element of the kill ring to nil. It does this by using two fun
tions,
nth
dr and set
dr.
We looked at set
dr earlier (see Se
tion 7.6, \set
dr", page 88). It sets
the
dr of a list, just as set
ar sets the
ar of a list. In this
ase, however,
set
dr will not be setting the
dr of the whole kill ring; the nth
dr fun
tion
is used to
ause it to set the
dr of the next to last element of the kill ring|
this means that sin
e the
dr of the next to last element is the last element
of the kill ring, it will set the last element of the kill ring.
The nth
dr fun
tion works by repeatedly taking the
dr of a list|it
takes the
dr of the
dr of the
dr . . . It does this N times and returns
the results.
108 Chapter 8: Cutting and Storing Text
Thus, if we had a four element list that was supposed to be three elements
long, we
ould set the
dr of the next to last element to nil, and thereby
shorten the list.
You
an see this by evaluating the following three expressions in turn.
First set the value of trees to (maple oak pine bir
h), then set the
dr
of its se
ond
dr to nil and then nd the value of trees:
(setq trees '(maple oak pine bir
h))
) (maple oak pine bir
h)
(set
dr (nth
dr 2 trees) nil)
) nil
trees
) (maple oak pine)
(The value returned by the set
dr expression is nil sin
e that is what the
dr is set to.)
To repeat, in kill-new, the nth
dr fun
tion takes the
dr a number of
times that is one less than the maximum permitted size of the kill ring and
sets the
dr of that element (whi
h will be the rest of the elements in the
kill ring) to nil. This prevents the kill ring from growing too long.
The next to last expression in the kill-new fun
tion is
(setq kill-ring-yank-pointer kill-ring)
The kill-ring-yank-pointer is a global variable that is set to be the
kill-ring.
Even though the kill-ring-yank-pointer is
alled a `pointer', it is
a variable just like the kill ring. However, the name has been
hosen to
help humans understand how the variable is used. The variable is used in
fun
tions su
h as yank and yank-pop (see Chapter 10, \Yanking Text Ba
k",
page 117).
Now, to return to the rst two lines in the body of the fun
tion:
(and (fboundp 'menu-bar-update-yank-menu)
(menu-bar-update-yank-menu string (and repla
e (
ar kill-ring))))
This is an expression whose rst element is the fun
tion and.
The and spe
ial form evaluates ea
h of its arguments until one of the
arguments returns a value of nil, in whi
h
ase the and expression returns
nil; however, if none of the arguments returns a value of nil, the value
resulting from evaluating the last argument is returned. (Sin
e su
h a value
is not nil, it is
onsidered true in Ema
s Lisp.) In other words, an and
expression returns a true value only if all its arguments are true.
In this
ase, the expression tests rst to see whether menu-bar-update-
yank-menu exists as a fun
tion, and if so,
alls it. The fboundp fun
tion
returns true if the symbol it is testing has a fun
tion denition that `is not
void'. If the symbol's fun
tion denition were void, we would re
eive an error
Review 109
8.6 Review
Here is a brief summary of some re
ently introdu
ed fun
tions.
ar
dr
ar returns the rst element of a list;
dr returns the se
ond
and subsequent elements of a list.
110 Chapter 8: Cutting and Storing Text
For example:
(
ar '(1 2 3 4 5 6 7))
) 1
(
dr '(1 2 3 4 5 6 7))
) (2 3 4 5 6 7)
nth
dr Return the result of taking
dr `n' times on a list. The nth
dr.
The `rest of the rest', as it were.
For example:
(nth
dr 3 '(1 2 3 4 5 6 7))
) (4 5 6 7)
set
ar
set
dr set
ar
hanges the rst element of a list; set
dr
hanges the
se
ond and subsequent elements of a list.
For example:
(setq triple '(1 2 3))
triple
) (37 2 3)
triple
) (37 "foo" "bar")
nil
bouquet
nil
In this example, the symbol bouquet holds the address of the rst pair of
boxes.
This same list
an be illustrated in a dierent sort of box notation like
this:
bouquet
(Symbols
onsist of more than pairs of addresses, but the stru
ture of
a symbol is made up of addresses. Indeed, the symbol bouquet
onsists of
a group of address-boxes, one of whi
h is the address of the printed word
`bouquet', a se
ond of whi
h is the address of a fun
tion denition atta
hed
to the symbol, if any, a third of whi
h is the address of the rst pair of
address-boxes for the list (rose violet butter
up), and so on. Here we
are showing that the symbol's third address-box points to the rst pair of
address-boxes for the list.)
If a symbol is set to the
dr of a list, the list itself is not
hanged; the
symbol simply has an address further down the list. (In the jargon,
ar and
dr are `non-destru
tive'.) Thus, evaluation of the following expression
(setq flowers (
dr bouquet))
produ
es this:
bouquet flowers
nil
The value of flowers is (violet butter
up), whi
h is to say, the symbol
flowers holds the address of the pair of address-boxes, the rst of whi
h
holds the address of violet, and the se
ond of whi
h holds the address of
butter
up.
A pair of address-boxes is
alled a
ons
ell or dotted pair. See se
tion
\List Type " in The GNU Ema
s Lisp Referen
e Manual, and se
tion \Dot-
ted Pair Notation" in The GNU Ema
s Lisp Referen
e Manual, for more
information about
ons
ells and dotted pairs.
The fun
tion
ons adds a new pair of addresses to the front of a series of
addresses like that shown above. For example, evaluating the expression
(setq bouquet (
ons 'lily bouquet))
produ
es:
bouquet flowers
nil
buttercup
lily violet
rose
However, this does not
hange the value of the symbol flowers, as you
an
see by evaluating the following,
(eq (
dr (
dr bouquet)) flowers)
whi
h returns t for true.
Until it is reset, flowers still has the value (violet butter
up); that
is, it has the address of the
ons
ell whose rst address is of violet. Also,
this does not alter any of the pre-existing
ons
ells; they are all still there.
Thus, in Lisp, to get the
dr of a list, you just get the address of the
next
ons
ell in the series; to get the
ar of a list, you get the address of
the rst element of the list; to
ons a new element on a list, you add a new
ons
ell to the front of the list. That is all there is to it! The underlying
stru
ture of Lisp is brilliantly simple!
And what does the last address in a series of
ons
ells refer to? It is the
address of the empty list, of nil.
In summary, when a Lisp variable is set to a value, it is provided with
the address of the list to whi
h the variable refers.
value in another, and so on. What is put in the drawer holding the value
an
be
hanged without ae
ting the
ontents of the drawer holding the fun
tion
denition, and vi
e-versa.
A
tually, what is put in ea
h drawer is the address of the value or fun
tion
denition. It is as if you found an old
hest in the atti
, and in one of its
drawers you found a map giving you dire
tions to where the buried treasure
lies.
(In addition to its name, symbol denition, and variable value, a symbol
has a `drawer' for a property list whi
h
an be used to re
ord other infor-
mation. Property lists are not dis
ussed here; see se
tion \Property Lists"
in The GNU Ema
s Lisp Referen
e Manual.)
Here is a fan
iful representation:
directions to map to
symbol name bouquet
directions to
symbol definition [none]
directions to map to
variable name (rose violet buttercup)
directions to
property list [not described here]
10 Yanking Text Ba
k
Whenever you
ut text out of a buer with a `kill'
ommand in GNU
Ema
s, you
an bring it ba
k with a `yank'
ommand. The text that is
ut
out of the buer is put in the kill ring and the yank
ommands insert the
appropriate
ontents of the kill ring ba
k into a buer (not ne
essarily the
original buer).
A simple C-y (yank)
ommand inserts the rst item from the kill ring into
the
urrent buer. If the C-y
ommand is followed immediately by M-y, the
rst element is repla
ed by the se
ond element. Su
essive M-y
ommands
repla
e the se
ond element with the third, fourth, or fth element, and so
on. When the last element in the kill ring is rea
hed, it is repla
ed by the
rst element and the
y
le is repeated. (Thus the kill ring is
alled a `ring'
rather than just a `list'. However, the a
tual data stru
ture that holds the
text is a list. See Appendix B, \Handling the Kill Ring", page 243, for the
details of how the list is handled as a ring.)
kill-ring kill-ring-yank-pointer
nil
yet more text
a different piece of text
some text
11.1 while
The while spe
ial form tests whether the value returned by evaluating
its rst argument is true or false. This is similar to what the Lisp interpreter
does with an if; what the interpreter does next, however, is dierent.
In a while expression, if the value returned by evaluating the rst argu-
ment is false, the Lisp interpreter skips the rest of the expression (the body
of the expression) and does not evaluate it. However, if the value is true, the
Lisp interpreter evaluates the body of the expression and then again tests
whether the rst argument to while is true or false. If the value returned
by evaluating the rst argument is again true, the Lisp interpreter again
evaluates the body of the expression.
The template for a while expression looks like this:
(while true-or-false-test
body ...)
So long as the true-or-false-test of the while expression returns a true
value when it is evaluated, the body is repeatedly evaluated. This pro
ess
is
alled a loop sin
e the Lisp interpreter repeats the same thing again and
again, like an airplane doing a loop. When the result of evaluating the true-
or-false-test is false, the Lisp interpreter does not evaluate the rest of the
while expression and `exits the loop'.
Clearly, if the value returned by evaluating the rst argument to while
is always true, the body following will be evaluated again and again . . .
and again . . . forever. Conversely, if the value returned is never true, the
1 You
an write re
ursive fun
tions to be frugal or wasteful of mental or
omputer
resour
es; as it happens, methods that people nd easy|that are frugal of `mental
resour
es'|sometimes use
onsiderable
omputer resour
es. Ema
s was designed to
run on ma
hines that we now
onsider limited and its default settings are
onservative.
You may want to in
rease the values of max-spe
pdl-size and max-lisp-eval-depth.
In my `.ema
s' le, I set them to 15 and 30 times their default value.
122 Chapter 11: Loops and Re
ursion
expressions in the body will never be evaluated. The
raft of writing a while
loop
onsists of
hoosing a me
hanism su
h that the true-or-false-test returns
true just the number of times that you want the subsequent expressions to
be evaluated, and then have the test return false.
The value returned by evaluating a while is the value of the true-or-false-
test. An interesting
onsequen
e of this is that a while loop that evaluates
without error will return nil or false regardless of whether it has looped 1 or
100 times or none at all. A while expression that evaluates su
essfully never
returns a true value! What this means is that while is always evaluated for
its side ee
ts, whi
h is to say, the
onsequen
es of evaluating the expressions
within the body of the while loop. This makes sense. It is not the mere a
t
of looping that is desired, but the
onsequen
es of what happens when the
expressions in the loop are repeatedly evaluated.
animals
Thus, to
reate a while loop that tests whether there are any items in
the list animals, the rst part of the loop will be written like this:
(while animals
...
An Example: print-elements-of-list 123
When the while tests its rst argument, the variable animals is evaluated.
It returns a list. So long as the list has elements, the while
onsiders the
results of the test to be true; but when the list is empty, it
onsiders the
results of the test to be false.
To prevent the while loop from running forever, some me
hanism needs
to be provided to empty the list eventually. An oft-used te
hnique is to have
one of the subsequent forms in the while expression set the value of the list
to be the
dr of the list. Ea
h time the
dr fun
tion is evaluated, the list
will be made shorter, until eventually only the empty list will be left. At
this point, the test of the while loop will return false, and the arguments to
the while will no longer be evaluated.
For example, the list of animals bound to the variable animals
an be
set to be the
dr of the original list with the following expression:
(setq animals (
dr animals))
If you have evaluated the previous expressions and then evaluate this ex-
pression, you will see (giraffe lion tiger) appear in the e
ho area. If you
evaluate the expression again, (lion tiger) will appear in the e
ho area. If
you evaluate it again and yet again, (tiger) appears and then the empty
list, shown by nil.
A template for a while loop that uses the
dr fun
tion repeatedly to
ause the true-or-false-test eventually to test false looks like this:
(while test-whether-list-is-empty
body ...
set-list-to-
dr-of-list)
This test and use of
dr
an be put together in a fun
tion that goes
through a list and prints ea
h element of the list on a line of its own.
(print-elements-of-list animals)
When you evaluate the three expressions in sequen
e, you will see this:
giraffe
gazelle
lion
tiger
nil
Ea
h element of the list is printed on a line of its own (that is what the
fun
tion print does) and then the value returned by the fun
tion is printed.
Sin
e the last expression in the fun
tion is the while loop, and sin
e while
loops always return nil, a nil is printed after the last element of the list.
(1+
ount) has the same result as (+
ount 1), but is easier for a human
to read.)
The template for a while loop
ontrolled by an in
rementing
ounter
looks like this:
set-
ount-to-initial-value
(while (<
ount desired-number) ; true-or-false-test
body ...
(setq
ount (1+
ount))) ; in
rementer
Note that you need to set the initial value of
ount; usually it is set to 1.
(About 2500 years ago, Pythagoras and others developed the beginnings of
number theory by
onsidering questions su
h as this.)
Suppose you want to know how many pebbles you will need to make a
triangle with 7 rows?
Clearly, what you need to do is add up the numbers from 1 to 7. There
are two ways to do this; start with the smallest number, one, and add up
the list in sequen
e, 1, 2, 3, 4 and so on; or start with the largest number
and add the list going down: 7, 6, 5, 4 and so on. Be
ause both me
hanisms
illustrate
ommon ways of writing while loops, we will
reate two examples,
one
ounting up and the other
ounting down. In this rst example, we will
start with 1 and add 2, 3, 4 and so on.
If you are just adding up a short list of numbers, the easiest way to do it
is to add up all the numbers at on
e. However, if you do not know ahead of
time how many numbers your list will have, or if you want to be prepared
for a very long list, then you need to design your addition so that what you
do is repeat a simple pro
ess many times instead of doing a more
omplex
pro
ess on
e.
For example, instead of adding up all the pebbles all at on
e, what you
an do is add the number of pebbles in the rst row, 1, to the number in the
se
ond row, 2, and then add the total of those two rows to the third row, 3.
Then you
an add the number in the fourth row, 4, to the total of the rst
three rows; and so on.
126 Chapter 11: Loops and Re
ursion
The
riti
al
hara
teristi
of the pro
ess is that ea
h repetitive a
tion is
simple. In this
ase, at ea
h step we add only two numbers, the number of
pebbles in the row and the total already found. This pro
ess of adding two
numbers is repeated again and again until the last row has been added to
the total of all the pre
eding rows. In a more
omplex loop the repetitive
a
tion might not be so simple, but it will be simpler than doing everything
all at on
e.
Lisp provides the <= fun
tion that returns true if the value of its rst
argument is less than or equal to the value of its se
ond argument and false
otherwise. So the expression that the while will evaluate as its test should
look like this:
(<= row-number number-of-rows)
The total number of pebbles
an be found by repeatedly adding the num-
ber of pebbles in a row to the total already found. Sin
e the number of
pebbles in the row is equal to the row number, the total
an be found by
adding the row number to the total. (Clearly, in a more
omplex situation,
the number of pebbles in the row might be related to the row number in
a more
ompli
ated way; if this were the
ase, the row number would be
repla
ed by the appropriate expression.)
(setq total (+ total row-number))
What this does is set the new value of total to be equal to the sum of
adding the number of pebbles in the row to the previous total.
After setting the value of total, the
onditions need to be established for
the next repetition of the loop, if there is one. This is done by in
rementing
the value of the row-number variable, whi
h serves as a
ounter. After
the row-number variable has been in
remented, the true-or-false-test at the
beginning of the while loop tests whether its value is still less than or equal
to the value of the number-of-rows and if it is, adds the new value of the
row-number variable to the total of the previous repetition of the loop.
The built-in Ema
s Lisp fun
tion 1+ adds 1 to a number, so the row-
number variable
an be in
remented with this expression:
(setq row-number (1+ row-number))
expression is part of the body of the while; it is the last element of the list
that starts with the symbol while. Moreover, the whole of the while loop
is a list within the body of the let.
In outline, the fun
tion will look like this:
(defun name-of-fun
tion (argument-list)
"do
umentation..."
(let (varlist)
(while (true-or-false-test)
body-of-while ... )
... ) ; Need nal expression here.
Putting everything together, the triangle fun
tion denition looks like
this:
(defun triangle (number-of-rows) ; Version with
; in
rementing
ounter.
"Add up the number of pebbles in a triangle.
The first row has one pebble, the se
ond row two pebbles,
the third row three pebbles, and so on.
The argument is NUMBER-OF-ROWS."
(let ((total 0)
(row-number 1))
(while (<= row-number number-of-rows)
(setq total (+ total row-number))
(setq row-number (1+ row-number)))
total))
Example with de
rementing
ounter 129
After you have installed triangle by evaluating the fun
tion, you
an
try it out. Here are two examples:
(triangle 4)
(triangle 7)
The sum of the rst four numbers is 10 and the sum of the rst seven numbers
is 28.
We know how many pebbles to start with: the number of pebbles in the
last row is equal to the number of rows. If the triangle has seven rows, the
number of pebbles in the last row is 7. Likewise, we know how many pebbles
are in the pre
eding row: it is one less than the number in the row.
dolist works like a while loop that `
drs down a list': dolist auto-
mati
ally shortens the list ea
h time it loops|takes the
dr of the list|and
binds the
ar of ea
h shorter version of the list to the rst of its arguments.
dotimes loops a spe
i
number of time: you spe
ify the number.
The dolist Ma
ro
Suppose, for example, you want to reverse a list, so that \rst" \se
ond"
\third" be
omes \third" \se
ond" \rst".
In pra
ti
e, you would use the reverse fun
tion, like this:
(setq animals '(gazelle giraffe lion tiger))
(reverse animals)
Here is how you
ould reverse the list using a while loop:
(setq animals '(gazelle giraffe lion tiger))
(reverse-list-with-while animals)
And here is how you
ould use the dolist ma
ro:
(setq animals '(gazelle giraffe lion tiger))
(reverse-list-with-dolist animals)
In Info, you
an pla
e your
ursor after the
losing parenthesis of ea
h ex-
pression and type C-x C-e; in ea
h
ase, you should see
(tiger lion giraffe gazelle)
in the e
ho area.
For this example, the existing reverse fun
tion is obviously best. The
while loop is just like our rst example (see Se
tion 11.1.1, \A while Loop
and a List", page 122). The while rst
he
ks whether the list has elements;
if so, it
onstru
ts a new list by adding the rst element of the list to the
The dotimes Ma
ro 133
existing list (whi
h in the rst iteration of the loop is nil). Sin
e the se
ond
element is prepended in front of the rst element, and the third element is
prepended in front of the se
ond element, the list is reversed.
In the expression using a while loop, the (setq list (
dr list)) ex-
pression shortens the list, so the while loop eventually stops. In addition,
it provides the
ons expression with a new rst element by
reating a new
and shorter list at ea
h repetition of the loop.
The dolist expression does very mu
h the same as the while expression,
ex
ept that the dolist ma
ro does some of the work you have to do when
writing a while expression.
Like a while loop, a dolist loops. What is dierent is that it automat-
i
ally shortens the list ea
h time it loops | it `
drs down the list' on its
own | and it automati
ally binds the
ar of ea
h shorter version of the list
to the rst of its arguments.
In the example, the
ar of ea
h shorter version of the list is referred
to using the symbol `element', the list itself is
alled `list', and the value
returned is
alled `value'. The remainder of the dolist expression is the
body.
The dolist expression binds the
ar of ea
h shorter version of the list
to element and then evaluates the body of the expression; and repeats the
loop. The result is returned in value.
The dotimes Ma
ro
The dotimes ma
ro is similar to dolist, ex
ept that it loops a spe
i
number of times.
The rst argument to dotimes is assigned the numbers 0, 1, 2 and so
forth ea
h time around the loop, and the value of the third argument is
returned. You need to provide the value of the se
ond argument, whi
h is
how many times the ma
ro loops.
For example, the following binds the numbers from 0 up to, but not
in
luding, the number 3 to the rst argument, number, and then
onstru
ts
a list of the three numbers. (The rst number is 0, the se
ond number is
1, and the third number is 2; this makes a total of three numbers in all,
starting with zero as the rst number.)
(let (value) ; otherwise a value is a void variable
(dotimes (number 3 value)
(setq value (
ons number value))))
) (2 1 0)
dotimes returns value, so the way to use dotimes is to operate on some
expression number number of times and then return the result, either as a
list or an atom.
134 Chapter 11: Loops and Re
ursion
(triangle-using-dotimes 4)
11.3 Re
ursion
A re
ursive fun
tion
ontains
ode that tells the Lisp interpreter to
all a
program that runs exa
tly like itself, but with slightly dierent arguments.
The
ode runs exa
tly the same be
ause it has the same name. However,
even though it has the same name, it is not the same thread of exe
ution.
It is dierent. In the jargon, it is a dierent `instan
e'.
Eventually, if the program is written
orre
tly, the `slightly dierent ar-
guments' will be
ome suÆ
iently dierent from the rst arguments that the
nal instan
e will stop.
Note that although we say that the fun
tion `
alls itself', what we mean
is that the Lisp interpreter assembles and instru
ts a new instan
e of the
program. The new instan
e is a
lone of the rst, but is a separate individual.
Ea
h time the fun
tion `invokes itself', it invokes itself on a shorter version
of the original list. It
reates a new instan
e that works on a shorter list.
Eventually, the fun
tion invokes itself on an empty list. It
reates a new
instan
e whose argument is nil. The
onditional expression tests the value
of list. Sin
e the value of list is nil, the if expression tests false so the
then-part is not evaluated. The fun
tion as a whole then returns nil.
When you evaluate (print-elements-re
ursively animals) in the
`*s
rat
h*' buer, you see this result:
giraffe
gazelle
lion
tiger
nil
(triangle-re
ursively 7)
You
an install this fun
tion by evaluating it and then try it by evaluating
(triangle-re
ursively 7). (Remember to put your
ursor immediately
after the last parenthesis of the fun
tion denition, before the
omment.)
The fun
tion evaluates to 28.
To understand how this fun
tion works, let's
onsider what happens in
the various
ases when the fun
tion is passed 1, 2, 3, or 4 as the value of its
argument.
First, what happens if the value of the argument is 1?
The fun
tion has an if expression after the do
umentation string. It
tests whether the value of number is equal to 1; if so, Ema
s evaluates the
138 Chapter 11: Loops and Re
ursion
An argument of 3 or 4
Suppose that triangle-re
ursively is
alled with an argument of 3.
Step 1 Evaluate the do-again-test.
The if expression is evaluated rst. This is the do-again test and
returns false, so the else-part of the if expression is evaluated.
(Note that in this example, the do-again-test
auses the fun
tion
to
all itself when it tests false, not when it tests true.)
Step 2 Evaluate the innermost expression of the else-part.
The innermost expression of the else-part is evaluated, whi
h
de
rements 3 to 2. This is the next-step-expression.
Re
ursion Example Using
ond 139
ond. The name of the spe
ial form
ond is an abbreviation of the word
`
onditional'.
Although the
ond spe
ial form is not used as often in the Ema
s Lisp
sour
es as if, it is used often enough to justify explaining it.
The template for a
ond expression looks like this:
(
ond
body ...)
where the body is a series of lists.
Written out more fully, the template looks like this:
(
ond
(rst-true-or-false-test rst-
onsequent)
(se
ond-true-or-false-test se
ond-
onsequent)
(third-true-or-false-test third-
onsequent)
...)
When the Lisp interpreter evaluates the
ond expression, it evaluates the
rst element (the
ar or true-or-false-test) of the rst expression in a series
of expressions within the body of the
ond.
If the true-or-false-test returns nil the rest of that expression, the
on-
sequent, is skipped and the true-or-false-test of the next expression is eval-
uated. When an expression is found whose true-or-false-test returns a value
that is not nil, the
onsequent of that expression is evaluated. The
onse-
quent
an be one or more expressions. If the
onsequent
onsists of more
than one expression, the expressions are evaluated in sequen
e and the value
of the last one is returned. If the expression does not have a
onsequent, the
value of the true-or-false-test is returned.
If none of the true-or-false-tests test true, the
ond expression returns
nil.
Written using
ond, the triangle fun
tion looks like this:
(defun triangle-using-
ond (number)
(
ond ((<= number 0) 0)
((= number 1) 1)
((> number 1)
(+ number (triangle-using-
ond (1- number))))))
In this example, the
ond returns 0 if the number is less than or equal to
0, it returns 1 if the number is 1 and it evaluates (+ number (triangle-
using-
ond (1- number))) if the number is greater than 1.
Here is example:
(defun square-ea
h (numbers-list)
"Square ea
h of a NUMBERS LIST, re
ursively."
(if (not numbers-list) ; do-again-test
nil
(
ons
(* (
ar numbers-list) (
ar numbers-list))
(square-ea
h (
dr numbers-list))))) ; next-step-expression
(square-ea
h '(1 2 3))
) (1 4 9)
Let's see what happens when we have a triangle that has one row. (This
triangle will have one pebble in it!)
triangle-initialization will
all its helper with the arguments 0 0 1.
That fun
tion will run the
onditional test whether (>
ounter number):
(> 0 1)
and nd that the result is false, so it will invoke the then-part of the if
lause:
(triangle-re
ursive-helper
(+ sum
ounter) ; sum plus
ounter ) sum
(1+
ounter) ; in
rement
ounter )
ounter
number) ; number stays the same
whi
h will rst
ompute:
(triangle-re
ursive-helper (+ 0 0) ; sum
(1+ 0) ;
ounter
1) ; number
whi
h is:
(triangle-re
ursive-helper 0 1 1)
Again, (>
ounter number) will be false, so again, the Lisp interpreter
will evaluate triangle-re
ursive-helper,
reating a new instan
e with
new arguments.
This new instan
e will be;
(triangle-re
ursive-helper
(+ sum
ounter) ; sum plus
ounter ) sum
(1+
ounter) ; in
rement
ounter )
ounter
number) ; number stays the same
whi
h is:
(triangle-re
ursive-helper 1 2 1)
In this
ase, the (>
ounter number) test will be true! So the instan
e
will return the value of the sum, whi
h will be 1, as expe
ted.
Now, let's pass triangle-initialization an argument of 2, to nd out
how many pebbles there are in a triangle with two rows.
That fun
tion
alls (triangle-re
ursive-helper 0 0 2).
In stages, the instan
es
alled will be:
sum
ounter number
(triangle-re
ursive-helper 0 1 2)
(triangle-re ursive-helper 1 2 2)
(triangle-re
ursive-helper 3 3 2)
Looping Exer
ise 147
When the last instan
e is
alled, the (>
ounter number) test will be
true, so the instan
e will return the value of sum, whi
h will be 3.
This kind of pattern helps when you are writing fun
tions that
an use
many resour
es in a
omputer.
Like sear
h-forward, the re-sear
h-forward fun
tion takes four argu-
ments:
1. The rst argument is the regular expression that the fun
tion sear
hes
for. The regular expression will be a string between quotations marks.
2. The optional se
ond argument limits how far the fun
tion will sear
h;
it is a bound, whi
h is spe
ied as a position in the buer.
3. The optional third argument spe
ies how the fun
tion responds to
failure: nil as the third argument
auses the fun
tion to signal an error
(and print a message) when the sear
h fails; any other value
auses it
to return nil if the sear
h fails and t if the sear
h su
eeds.
4. The optional fourth argument is the repeat
ount. A negative repeat
ount
auses re-sear
h-forward to sear
h ba
kwards.
The template for re-sear
h-forward looks like this:
(re-sear
h-forward "regular-expression"
limit-of-sear
h
what-to-do-if-sear
h-fails
repeat-
ount)
The se
ond, third, and fourth arguments are optional. However, if you
want to pass a value to either or both of the last two arguments, you must also
pass a value to all the pre
eding arguments. Otherwise, the Lisp interpreter
will mistake whi
h argument you are passing the value to.
In the forward-senten
e fun
tion, the regular expression will be the
value of the variable senten
e-end, namely:
"[.?!℄[℄\"')}℄*\\($\\| \\| \\)[
℄*"
The limit of the sear
h will be the end of the paragraph (sin
e a senten
e
annot go beyond a paragraph). If the sear
h fails, the fun
tion will return
nil; and the repeat
ount will be provided by the argument to the forward-
senten
e fun
tion.
12.3 forward-senten
e
The
ommand to move the
ursor forward a senten
e is a straightforward
illustration of how to use regular expression sear
hes in Ema
s Lisp. Indeed,
the fun
tion looks longer and more
ompli
ated than it is; this is be
ause the
fun
tion is designed to go ba
kwards as well as forwards; and, optionally, over
more than one senten
e. The fun
tion is usually bound to the key
ommand
M-e.
152 Chapter 12: Regular Expression Sear
hes
But rst, let us examine how par-end is bound to the value of the end
of the paragraph. What happens is that the let sets the value of par-end
to the value returned when the Lisp interpreter evaluates the expression
(save-ex
ursion (end-of-paragraph-text) (point))
In this expression, (end-of-paragraph-text) moves point to the end of the
paragraph, (point) returns the value of point, and then save-ex
ursion
restores point to its original position. Thus, the let binds par-end to the
value returned by the save-ex
ursion expression, whi
h is the position of
the end of the paragraph. (The (end-of-paragraph-text) fun
tion uses
forward-paragraph, whi
h we will dis
uss shortly.)
Ema
s next evaluates the body of the let, whi
h is an if expression that
looks like this:
(if (re-sear
h-forward senten
e-end par-end t) ; if-part
(skip-
hars-ba
kward " \t\n") ; then-part
(goto-
har par-end))) ; else-part
The if tests whether its rst argument is true and if so, evaluates its
then-part; otherwise, the Ema
s Lisp interpreter evaluates the else-part.
The true-or-false-test of the if expression is the regular expression sear
h.
It may seem odd to have what looks like the `real work' of the forward-
senten
e fun
tion buried here, but this is a
ommon way this kind of oper-
ation is
arried out in Lisp.
The regular expression sear
h
The re-sear
h-forward fun
tion sear
hes for the end of the senten
e,
that is, for the pattern dened by the senten
e-end regular expression.
If the pattern is found|if the end of the senten
e is found|then the re-
sear
h-forward fun
tion does two things:
1. The re-sear
h-forward fun
tion
arries out a side ee
t, whi
h is to
move point to the end of the o
urren
e found.
2. The re-sear
h-forward fun
tion returns a value of true. This is the
value re
eived by the if, and means that the sear
h was su
essful.
The side ee
t, the movement of point, is
ompleted before the if fun
tion
is handed the value returned by the su
essful
on
lusion of the sear
h.
When the if fun
tion re
eives the value of true from a su
essful
all to
re-sear
h-forward, the if evaluates the then-part, whi
h is the expression
(skip-
hars-ba
kward " \t\n"). This expression moves ba
kwards over
any blank spa
es, tabs or
arriage returns until a printed
hara
ter is found
and then leaves point after the
hara
ter. Sin
e point has already been
moved to the end of the pattern that marks the end of the senten
e, this
a
tion leaves point right after the
losing printed
hara
ter of the senten
e,
whi
h is usually a period.
On the other hand, if the re-sear
h-forward fun
tion fails to nd a
pattern marking the end of the senten
e, the fun
tion returns false. The
forward-paragraph: a Goldmine of Fun
tions 155
false then
auses the if to evaluate its third argument, whi
h is (goto-
har
par-end): it moves point to the end of the paragraph.
Regular expression sear
hes are ex
eptionally useful and the pattern il-
lustrated by re-sear
h-forward, in whi
h the sear
h is the test of an if
expression, is handy. You will see or write
ode in
orporating this pattern
often.
The rst parts of the fun
tion are routine: the fun
tion's argument list
onsists of one optional argument. Do
umentation follows.
The lower
ase `p' in the intera
tive de
laration means that the pro-
essed prex argument, if any, is passed to the fun
tion. This will be a
number, and is the repeat
ount of how many paragraphs point will move.
The or expression in the next line handles the
ommon
ase when no argu-
ment is passed to the fun
tion, whi
h o
urs if the fun
tion is
alled from
other
ode rather than intera
tively. This
ase was des
ribed earlier. (See
Se
tion 12.3, \forward-senten
e", page 151.) Now we rea
h the end of the
familiar part of this fun
tion.
fill-prefix
When this variable is evaluated, the value of the ll prex, if
any, is returned. If there is no ll prex, this variable returns
nil.
(not (equal fill-prefix "")
This expression
he
ks whether an existing ll prex is an empty
string, that is, a string with no
hara
ters in it. An empty string
is not a useful ll prex.
(not paragraph-ignore-fill-prefix)
This expression returns nil if the variable paragraph-ignore-
fill-prefix has been turned on by being set to a true value
su
h as t.
(regexp-quote fill-prefix)
This is the last argument to the and spe
ial form. If all the
arguments to the and are true, the value resulting from evaluat-
ing this expression will be returned by the and expression and
bound to the variable fill-prefix-regexp,
The result of evaluating this and expression su
essfully is that fill-
prefix-regexp will be bound to the value of fill-prefix as modied by
the regexp-quote fun
tion. What regexp-quote does is read a string and
return a regular expression that will exa
tly mat
h the string and mat
h
nothing else. This means that fill-prefix-regexp will be set to a value
that will exa
tly mat
h the ll prex if the ll prex exists. Otherwise, the
variable will be set to nil.
The se
ond lo
al variable in the let* expression is paragraph-separate.
It is bound to the value returned by evaluating the expression:
(if fill-prefix-regexp
(
on
at paragraph-separate
"\\|^" fill-prefix-regexp "[ \t℄*$")
paragraph-separate)))
This expression shows why let* rather than let was used. The true-or-
false-test for the if depends on whether the variable fill-prefix-regexp
evaluates to nil or some other value.
If fill-prefix-regexp does not have a value, Ema
s evaluates the else-
part of the if expression and binds paragraph-separate to its lo
al value.
(paragraph-separate is a regular expression that mat
hes what separates
paragraphs.)
But if fill-prefix-regexp does have a value, Ema
s evaluates the then-
part of the if expression and binds paragraph-separate to a regular ex-
pression that in
ludes the fill-prefix-regexp as part of the pattern.
Spe
i
ally, paragraph-separate is set to the original value of the para-
graph separate regular expression
on
atenated with an alternative expres-
sion that
onsists of the fill-prefix-regexp followed by a blank line. The
158 Chapter 12: Regular Expression Sear
hes
`^' indi
ates that the fill-prefix-regexp must begin a line, and the op-
tional whitespa
e to the end of the line is dened by "[ \t℄*$".) The `\\|'
denes this portion of the regexp as an alternative to paragraph-separate.
Now we get into the body of the let*. The rst part of the body of the
let* deals with the
ase when the fun
tion is given a negative argument and
is therefore moving ba
kwards. We will skip this se
tion.
;; between paragraphs
(while (prog1 (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
;; within paragraphs, with a ll prex
(if fill-prefix-regexp
;; There is a ll prex; it overrides paragraph-start.
(while (and (not (eobp))
(not (looking-at paragraph-separate))
(looking-at fill-prefix-regexp))
(forward-line 1))
;; within paragraphs, no ll prex
(if (re-sear
h-forward paragraph-start nil t)
(goto-
har (mat
h-beginning 0))
(goto-
har (point-max))))
Between paragraphs
First, let us look at the inner while loop. This loop handles the
ase
when point is between paragraphs; it uses three fun
tions that are new to
us: prog1, eobp and looking-at.
prog1 is similar to the progn spe
ial form, ex
ept that prog1 evaluates
its arguments in sequen
e and then returns the value of its rst argument
as the value of the whole expression. (progn returns the value of its last
argument as the value of the expression.) The se
ond and subsequent
arguments to prog1 are evaluated only for their side ee
ts.
eobp is an abbreviation of `End Of Buffer P' and is a fun
tion that
returns true if point is at the end of the buer.
looking-at is a fun
tion that returns true if the text following point
mat
hes the regular expression passed looking-at as its argument.
The while loop we are studying looks like this:
(while (prog1 (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
This is a while loop with no body! The true-or-false-test of the loop is the
expression:
(prog1 (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1))
The rst argument to the prog1 is the and expression. It has within in it a
test of whether point is at the end of the buer and also a test of whether
160 Chapter 12: Regular Expression Sear
hes
the pattern following point mat
hes the regular expression for separating
paragraphs.
If the
ursor is not at the end of the buer and if the
hara
ters fol-
lowing the
ursor mark the separation between two paragraphs, then the
and expression is true. After evaluating the and expression, the Lisp inter-
preter evaluates the se
ond argument to prog1, whi
h is forward-line. This
moves point forward one line. The value returned by the prog1 however, is
the value of its rst argument, so the while loop
ontinues so long as point
is not at the end of the buer and is between paragraphs. When, nally,
point is moved to a paragraph, the and expression tests false. Note however,
that the forward-line
ommand is
arried out anyhow. This means that
when point is moved from between paragraphs to a paragraph, it is left at
the beginning of the se
ond line of the paragraph.
Within paragraphs
The next expression in the outer while loop is an if expression. The
Lisp interpreter evaluates the then-part of the if when the fill-prefix-
regexp variable has a value other than nil, and it evaluates the else-part
when the value of if fill-prefix-regexp is nil, that is, when there is no
ll prex.
No ll prex
It is simplest to look at the
ode for the
ase when there is no ll prex
rst. This
ode
onsists of yet another inner if expression, and reads as
follows:
(if (re-sear
h-forward paragraph-start nil t)
(goto-
har (mat
h-beginning 0))
(goto-
har (point-max)))
This expression a
tually does the work that most people think of as the
primary purpose of the forward-paragraph
ommand: it
auses a regular
expression sear
h to o
ur that sear
hes forward to the start of the next
paragraph and if it is found, moves point there; but if the start of another
paragraph if not found, it moves point to the end of the a
essible region of
the buer.
The only unfamiliar part of this is the use of mat
h-beginning. This is
another fun
tion that is new to us. The mat
h-beginning fun
tion returns
a number spe
ifying the lo
ation of the start of the text that was mat
hed
by the last regular expression sear
h.
The mat
h-beginning fun
tion is used here be
ause of a
hara
teristi
of a forward sear
h: a su
essful forward sear
h, regardless of whether it is
a plain sear
h or a regular expression sear
h, will move point to the end of
the text that is found. In this
ase, a su
essful sear
h will move point to
Summary 161
the end of the pattern for paragraph-start, whi
h will be the beginning of
the next paragraph rather than the end of the
urrent one.
However, we want to put point at the end of the
urrent paragraph, not at
the beginning of the next one. The two positions may be dierent, be
ause
there may be several blank lines between paragraphs.
When given an argument of 0, mat
h-beginning returns the position
that is the start of the text that the most re
ent regular expression sear
h
mat
hed. In this
ase, the most re
ent regular expression sear
h is the one
looking for paragraph-start, so mat
h-beginning returns the beginning
position of the pattern, rather than the end of the pattern. The beginning
position is the end of the paragraph.
(In
identally, when passed a positive number as an argument, the mat
h-
beginning fun
tion will pla
e point at that parenthesized expression in the
last regular expression. It is a useful fun
tion.)
With a ll prex
The inner if expression just dis
ussed is the else-part of an en
losing if
expression whi
h tests whether there is a ll prex. If there is a ll prex,
the then-part of this if is evaluated. It looks like this:
(while (and (not (eobp))
(not (looking-at paragraph-separate))
(looking-at fill-prefix-regexp))
(forward-line 1))
What this expression does is move point forward line by line so long as three
onditions are true:
1. Point is not at the end of the buer.
2. The text following point does not separate paragraphs.
3. The pattern following point is the ll prex regular expression.
The last
ondition may be puzzling, until you remember that point was
moved to the beginning of the line early in the forward-paragraph fun
tion.
This means that if the text has a ll prex, the looking-at fun
tion will
see it.
Summary
In summary, when moving forward, the forward-paragraph fun
tion
does the following:
Move point to the beginning of the line.
Skip over lines between paragraphs.
Che
k whether there is a ll prex, and if there is:
| Go forward line by line so long as the line is not a paragraph sep-
arating line.
162 Chapter 12: Regular Expression Sear
hes
If you are reading this inside of GNU Ema
s and you want to see the
whole fun
tion, you
an type C-h f (des
ribe-fun
tion) and the name of
the fun
tion. This gives you the fun
tion do
umentation and the name of
the library
ontaining the fun
tion's sour
e. Pla
e point over the name of
the library and press the RET key; you will be taken dire
tly to the sour
e.
(Be sure to install your sour
es! Without them, you are like a person who
tries to drive a
ar with his eyes shut!)
Or { a good habit to get into { you
an type M-. (find-tag) and
the name of the fun
tion when prompted for it. This will take you di-
re
tly to the sour
e. If the find-tag fun
tion rst asks you for the
name of a `TAGS' table, give it the name of the `TAGS' le su
h as
`/usr/lo
al/share/ema
s/21.0.100/lisp/TAGS'. (The exa
t path to your
`TAGS' le depends on how your
opy of Ema
s was installed.)
You
an also
reate your own `TAGS' le for dire
tories that la
k one.
Type
M-x
ompile RET etags --help RET
to see a list of the options a
epted by etags as well as a list of supported
languages.
The etags program handles more than 20 languages, in
luding Ema
s
Lisp, Common Lisp, S
heme, C, C++, Ada, Fortran, Java, LaTeX, Pas
al,
Perl, Python, Texinfo, makeles, and most assemblers. The program has no
swit
hes for spe
ifying the language; it re
ognizes the language in an input
le a
ording to its le name and
ontents.
`etags' is very helpful when you are writing
ode yourself and want to
refer ba
k to fun
tions you have already written. Just run etags again at
intervals as you write new fun
tions, so they be
ome part of the `TAGS' le.
If you think an appropriate `TAGS' le already exists for what you want,
but do not know where it is, you
an use the lo
ate program to attempt to
nd it.
Type M-x lo
ate RET TAGS RET and Ema
s will list for you the full path
names of all your `TAGS' les. On my system, this
ommand lists 34 `TAGS'
les. On the other hand, a `plain vanilla' system I re
ently installed did not
ontain any `TAGS' les.
If the tags table you want has been
reated, you
an use the M-x visit-
tags-table
ommand to spe
ify it. Otherwise, you will need to
reate the
tag table yourself and then use M-x visit-tags-table.
12.6 Review
Here is a brief summary of some re
ently introdu
ed fun
tions.
while Repeatedly evaluate the body of the expression so long as the
rst element of the body tests true. Then return nil. (The
expression is evaluated only for its side ee
ts.)
Review 165
For example:
(let ((foo 2))
(while (> foo 0)
(insert (format "foo is %d.\n" foo))
(setq foo (1- foo))))
) foo is 2.
foo is 1.
nil
(The insert fun
tion inserts its arguments at point; the format
fun
tion returns a string formatted from its arguments the way
message formats its arguments; \n produ
es a new line.)
re-sear
h-forward
Sear
h for a pattern, and if the pattern is found, move point to
rest just after it.
Takes four arguments, like sear
h-forward:
1. A regular expression that spe
ies the pattern to sear
h for.
2. Optionally, the limit of the sear
h.
3. Optionally, what to do if the sear
h fails, return nil or an
error message.
4. Optionally, how many times to repeat the sear
h; if nega-
tive, the sear
h goes ba
kwards.
let* Bind some variables lo
ally to parti
ular values, and then eval-
uate the remaining arguments, returning the value of the last
one. While binding the lo
al variables, use the lo
al values of
variables bound earlier, if any.
For example:
(let* ((foo 7)
(bar (* 3 foo)))
(message "`bar' is %d." bar))
) `bar' is 21.
mat
h-beginning
Return the position of the start of the text found by the last
regular expression sear
h.
looking-at
Return t for true if the text after point mat
hes the argument,
whi
h should be a regular expression.
eobp Return t for true if point is at the end of the a
essible part of
a buer. The end of the a
essible part is the end of the buer
if the buer is not narrowed; it is the end of the narrowed part
if the buer is narrowed.
166 Chapter 12: Regular Expression Sear
hes
The fun
tion
ounts words within a region. This means that the argument
list must
ontain symbols that are bound to the two positions, the beginning
and end of the region. These two positions
an be
alled `beginning' and
`end' respe
tively. The rst line of the do
umentation should be a single sen-
ten
e, sin
e that is all that is printed as do
umentation by a
ommand su
h
as apropos. The intera
tive expression will be of the form `(intera
tive
"r")', sin
e that will
ause Ema
s to pass the beginning and end of the
region to the fun
tion's argument list. All this is routine.
The body of the fun
tion needs to be written to do three tasks: rst, to
set up
onditions under whi
h the while loop
an
ount words, se
ond, to
run the while loop, and third, to send a message to the user.
When a user
alls
ount-words-region, point may be at the beginning
or the end of the region. However, the
ounting pro
ess must start at the
beginning of the region. This means we will want to put point there if
it is not already there. Exe
uting (goto-
har beginning) ensures this.
Of
ourse, we will want to return point to its expe
ted position when the
fun
tion nishes its work. For this reason, the body must be en
losed in a
save-ex
ursion expression.
The
entral part of the body of the fun
tion
onsists of a while loop
in whi
h one expression jumps point forward word by word, and another
expression
ounts those jumps. The true-or-false-test of the while loop
should test true so long as point should jump forward, and false when point
is at the end of the region.
We
ould use (forward-word 1) as the expression for moving point for-
ward word by word, but it is easier to see what Ema
s identies as a `word'
if we use a regular expression sear
h.
A regular expression sear
h that nds the pattern for whi
h it is sear
hing
leaves point after the last
hara
ter mat
hed. This means that a su
ession
of su
essful word sear
hes will move point forward word by word.
As a pra
ti
al matter, we want the regular expression sear
h to jump
over whitespa
e and pun
tuation between words as well as over the words
themselves. A regexp that refuses to jump over interword whitespa
e would
never jump more than one word! This means that the regexp should in
lude
the whitespa
e and pun
tuation that follows a word, if any, as well as the
word itself. (A word may end a buer and not have any following whitespa
e
or pun
tuation, so that part of the regexp must be optional.)
Thus, what we want for the regexp is a pattern dening one or more word
onstituent
hara
ters followed, optionally, by one or more
hara
ters that
are not word
onstituents. The regular expression for this is:
\w+\W*
The buer's syntax table determines whi
h
hara
ters are and are not word
onstituents. (See Se
tion 14.2, \What Constitutes a Word or Symbol?",
page 182, for more about syntax. Also, see se
tion \The Syntax Table" in
The
ount-words-region Fun
tion 169
The GNU Ema
s Manual, and se
tion \Syntax Tables" in The GNU Ema
s
Lisp Referen
e Manual.)
The sear
h expression looks like this:
(re-sear
h-forward "\\w+\\W*")
(Note that paired ba
kslashes pre
ede the `w' and `W'. A single ba
kslash
has spe
ial meaning to the Ema
s Lisp interpreter. It indi
ates that the fol-
lowing
hara
ter is interpreted dierently than usual. For example, the two
hara
ters, `\n', stand for `newline', rather than for a ba
kslash followed by
`n'. Two ba
kslashes in a row stand for an ordinary, `unspe
ial' ba
kslash.)
We need a
ounter to
ount how many words there are; this variable
must rst be set to 0 and then in
remented ea
h time Ema
s goes around
the while loop. The in
rementing expression is simply:
(setq
ount (1+
ount))
Finally, we want to tell the user how many words there are in the region.
The message fun
tion is intended for presenting this kind of information to
the user. The message has to be phrased so that it reads properly regardless
of how many words there are in the region: we don't want to say that \there
are 1 words in the region". The
on
i
t between singular and plural is
ungrammati
al. We
an solve this problem by using a
onditional expression
that evaluates dierent messages depending on the number of words in the
region. There are three possibilities: no words in the region, one word in the
region, and more than one word. This means that the
ond spe
ial form is
appropriate.
All this leads to the following fun
tion denition:
;;; First version; has bugs!
(defun
ount-words-region (beginning end)
"Print number of words in the region.
Words are defined as at least one word-
onstituent
hara
ter followed by at least one
hara
ter that
is not a word-
onstituent. The buffer's syntax
table determines whi
h
hara
ters these are."
(intera
tive "r")
(message "Counting words in region ... ")
;;; 1. Set up appropriate
onditions.
(save-ex
ursion
(goto-
har beginning)
(let ((
ount 0))
;;; 2. Run the while loop.
(while (< (point) end)
(re-sear
h-forward "\\w+\\W*")
(setq
ount (1+
ount)))
170 Chapter 13: Counting: Repetition and Regexps
sin
e it is
omposed only of the whitespa
e at the end of the line. Instead,
Ema
s displays an error message saying `Sear
h failed'.
The two bugs stem from the same problem.
Consider the rst manifestation of the bug, in whi
h the
ommand tells
you that the whitespa
e at the beginning of the line
ontains one word.
What happens is this: The M-x
ount-words-region
ommand moves point
to the beginning of the region. The while tests whether the value of point
is smaller than the value of end, whi
h it is. Consequently, the regular
expression sear
h looks for and nds the rst word. It leaves point after the
word.
ount is set to one. The while loop repeats; but this time the value
of point is larger than the value of end, the loop is exited; and the fun
tion
displays a message saying the number of words in the region is one. In brief,
the regular expression sear
h looks for and nds the word even though it is
outside the marked region.
In the se
ond manifestation of the bug, the region is whitespa
e at the
end of the buer. Ema
s says `Sear
h failed'. What happens is that the
true-or-false-test in the while loop tests true, so the sear
h expression is
exe
uted. But sin
e there are no more words in the buer, the sear
h fails.
In both manifestations of the bug, the sear
h extends or attempts to
extend outside of the region.
The solution is to limit the sear
h to the region|this is a fairly simple
a
tion, but as you may have
ome to expe
t, it is not quite as simple as you
might think.
As we have seen, the re-sear
h-forward fun
tion takes a sear
h pattern
as its rst argument. But in addition to this rst, mandatory argument, it
a
epts three optional arguments. The optional se
ond argument bounds the
sear
h. The optional third argument, if t,
auses the fun
tion to return nil
rather than signal an error if the sear
h fails. The optional fourth argument
is a repeat
ount. (In Ema
s, you
an see a fun
tion's do
umentation by
typing C-h f, the name of the fun
tion, and then hRETi.)
In the
ount-words-region denition, the value of the end of the region
is held by the variable end whi
h is passed as an argument to the fun
-
tion. Thus, we
an add end as an argument to the regular expression sear
h
expression:
(re-sear
h-forward "\\w+\\W*" end)
However, if you make only this
hange to the
ount-words-region deni-
tion and then test the new version of the denition on a stret
h of whitespa
e,
you will re
eive an error message saying `Sear
h failed'.
What happens is this: the sear
h is limited to the region, and fails as
you expe
t be
ause there are no word-
onstituent
hara
ters in the region.
Sin
e it fails, we re
eive an error message. But we do not want to re
eive an
error message in this
ase; we want to re
eive the message that "The region
does NOT have any words."
172 Chapter 13: Counting: Repetition and Regexps
We
an readily
onstru
t a template for this fun
tion, based on our pre-
vious versions:
The denition looks straightforward, ex
ept that somehow the
ount re-
turned by the re
ursive
all must be passed to the message displaying the
word
ount. A little thought suggests that this
an be done by making use
of a let expression: we
an bind a variable in the varlist of a let expression
to the number of words in the region, as returned by the re
ursive
all; and
then the
ond expression, using binding,
an display the value to the user.
word, plus the number returned when it
ounts the remaining words in
the region, whi
h in this
ase is zero.
If there are no words in the region, the fun
tion should return zero.
From the sket
h we
an see that the else-part of the if returns zero for
the
ase of no words. This means that the then-part of the if must return
a value resulting from adding one to the value returned from a
ount of the
remaining words.
The expression will look like this, where 1+ is a fun
tion that adds one
to its argument.
(1+ (re
ursive-
ount-words region-end))
The whole re
ursive-
ount-words fun
tion will then look like this:
(defun re
ursive-
ount-words (region-end)
"do
umentation..."
;;; 1. do-again-test
(if (and (< (point) region-end)
(re-sear
h-forward "\\w+\\W*" region-end t))
;;; 2. then-part: the re
ursive
all
(1+ (re
ursive-
ount-words region-end))
;;; 3. else-part
0))
Let's examine how this works:
If there are no words in the region, the else part of the if expression is
evaluated and
onsequently the fun
tion returns zero.
If there is one word in the region, the value of point is less than the value
of region-end and the sear
h su
eeds. In this
ase, the true-or-false-test
of the if expression tests true, and the then-part of the if expression is
evaluated. The
ounting expression is evaluated. This expression returns a
value (whi
h will be the value returned by the whole fun
tion) that is the
sum of one added to the value returned by a re
ursive
all.
Meanwhile, the next-step-expression has
aused point to jump over the
rst (and in this
ase only) word in the region. This means that when
(re
ursive-
ount-words region-end) is evaluated a se
ond time, as a
result of the re
ursive
all, the value of point will be equal to or greater
than the value of region end. So this time, re
ursive-
ount-words will
return zero. The zero will be added to one, and the original evaluation of
re
ursive-
ount-words will return one plus zero, whi
h is one, whi
h is
the
orre
t amount.
Clearly, if there are two words in the region, the rst
all to re
ursive-
ount-words returns one added to the value returned by
alling re
ursive-
ount-words on a region
ontaining the remaining word|that is, it adds
one to one, produ
ing two, whi
h is the
orre
t amount.
178 Chapter 13: Counting: Repetition and Regexps
Similarly, if there are three words in the region, the rst
all to
re
ursive-
ount-words returns one added to the value returned by
alling
re
ursive-
ount-words on a region
ontaining the remaining two words|
and so on and so on.
With full do umentation the two fun tions look like this:
;;; 3. else-part
0))
The wrapper:
the fun
tion determine whether it is
alled when point is within a fun
tion
denition, and if it is, to return the
ount for that denition. This adds
omplexity to the denition, but saves us from needing to pass arguments
to the fun
tion.
These
onsiderations lead us to prepare the following template:
(defun
ount-words-in-defun ()
"do
umentation..."
(set up...
(while loop...)
return
ount)
As usual, our job is to ll in the slots.
First, the set up.
We are presuming that this fun
tion will be
alled within a buer
on-
taining fun
tion denitions. Point will either be within a fun
tion denition
or not. For
ount-words-in-defun to work, point must move to the begin-
ning of the denition, a
ounter must start at zero, and the
ounting loop
must stop when point rea
hes the end of the denition.
The beginning-of-defun fun
tion sear
hes ba
kwards for an opening
delimiter su
h as a `(' at the beginning of a line, and moves point to that
position, or else to the limit of the sear
h. In pra
ti
e, this means that
beginning-of-defun moves point to the beginning of an en
losing or pre-
eding fun
tion denition, or else to the beginning of the buer. We
an use
beginning-of-defun to pla
e point where we wish to start.
The while loop requires a
ounter to keep tra
k of the words or symbols
being
ounted. A let expression
an be used to
reate a lo
al variable for
this purpose, and bind it to an initial value of zero.
The end-of-defun fun
tion works like beginning-of-defun ex
ept that
it moves point to the end of the denition. end-of-defun
an be used as part
of an expression that determines the position of the end of the denition.
The set up for
ount-words-in-defun takes shape rapidly: rst we move
point to the beginning of the denition, then we
reate a lo
al variable to
hold the
ount, and nally, we re
ord the position of the end of the denition
so the while loop will know when to stop looping.
The
ode looks like this:
(beginning-of-defun)
(let ((
ount 0)
(end (save-ex
ursion (end-of-defun) (point))))
The
ode is simple. The only slight
ompli
ation is likely to
on
ern end: it
is bound to the position of the end of the denition by a save-ex
ursion
expression that returns the value of point after end-of-defun temporarily
moves it to the end of the denition.
The se
ond part of the
ount-words-in-defun, after the set up, is the
while loop.
The
ount-words-in-defun Fun
tion 185
The loop must
ontain an expression that jumps point forward word by
word and symbol by symbol, and another expression that
ounts the jumps.
The true-or-false-test for the while loop should test true so long as point
should jump forward, and false when point is at the end of the denition.
We have already redened the regular expression for this (see Se
tion 14.2,
\Syntax", page 182), so the loop is straightforward:
(while (and (< (point) end)
(re-sear
h-forward
"\\(\\w\\|\\s_\\)+[^ \t\n℄*[ \t\n℄*" end t)
(setq
ount (1+
ount)))
The third part of the fun
tion denition returns the
ount of words and
symbols. This part is the last expression within the body of the let expres-
sion, and
an be, very simply, the lo
al variable
ount, whi
h when evaluated
returns the
ount.
Put together, the
ount-words-in-defun denition looks like this:
(defun
ount-words-in-defun ()
"Return the number of words and symbols in a defun."
(beginning-of-defun)
(let ((
ount 0)
(end (save-ex
ursion (end-of-defun) (point))))
(while
(and (< (point) end)
(re-sear
h-forward
"\\(\\w\\|\\s_\\)+[^ \t\n℄*[ \t\n℄*"
end t))
(setq
ount (1+
ount)))
ount))
How to test this? The fun
tion is not intera
tive, but it is easy to put a
wrapper around the fun
tion to make it intera
tive; we
an use almost the
same
ode as for the re
ursive version of
ount-words-region:
;;; Intera
tive version.
(defun
ount-words-defun ()
"Number of words and symbols in a fun
tion definition."
(intera
tive)
(message
"Counting words and symbols in fun
tion definition ... ")
(let ((
ount (
ount-words-in-defun)))
(
ond
((zerop
ount)
(message
"The definition does NOT have any words or symbols."))
186 Chapter 14: Counting Words in a defun
((= 1
ount)
(message
"The definition has 1 word or symbol."))
(t
(message
"The definition has %d words or symbols."
ount)))))
Let's re-use C-
= as a
onvenient keybinding:
(global-set-key "\C-
=" '
ount-words-defun)
Now we
an try out
ount-words-defun: install both
ount-words-in-
defun and
ount-words-defun, and set the keybinding, and then pla
e the
ursor within the following denition:
(defun multiply-by-seven (number)
"Multiply NUMBER by seven."
(* 7 number))
) 10
Su
ess! The denition has 10 words and symbols.
The next problem is to
ount the numbers of words and symbols in several
denitions within a single le.
in
onvenient if they are inadvertently modied. It goes without saying that
I did not realize a need for this line until an experiment went awry and
started to modify my Ema
s sour
e les . . .
Next
omes a
all to widen the buer if it is narrowed. This fun
tion
is usually not needed|Ema
s
reates a fresh buer if none already exists;
but if a buer visiting the le already exists Ema
s returns that one. In
this
ase, the buer may be narrowed and must be widened. If we wanted
to be fully `user-friendly', we would arrange to save the restri
tion and the
lo
ation of point, but we won't.
The (goto-
har (point-min)) expression moves point to the beginning
of the buer.
Then
omes a while loop in whi
h the `work' of the fun
tion is
arried out.
In the loop, Ema
s determines the length of ea
h denition and
onstru
ts
a lengths' list
ontaining the information.
Ema
s kills the buer after working through it. This is to save spa
e
inside of Ema
s. My version of Ema
s 19
ontained over 300 sour
e les
of interest; Ema
s 21
ontains over 800 sour
e les. Another fun
tion will
apply lengths-list-file to ea
h of the les.
Finally, the last expression within the let expression is the lengths-list
variable; its value is returned as the value of the whole fun
tion.
You
an try this fun
tion by installing it in the usual fashion. Then pla
e
your
ursor after the following expression and type C-x C-e (eval-last-
sexp).
(lengths-list-file
"/usr/lo
al/share/ema
s/21.0.100/lisp/ema
s-lisp/debug.el")
(You may need to
hange the pathname of the le; the one here worked
with GNU Ema
s version 21.0.100. To
hange the expression,
opy it to the
`*s
rat
h*' buer and edit it.
(Also, to see the full length of the list, rather than a trun
ated version, you
may have to evaluate the following:
(
ustom-set-variables '(eval-expression-print-length nil))
(See Se
tion 16.2, \Setting Variables with def
ustom", page 214. Then
evaluate the lengths-list-file expression.)
190 Chapter 14: Counting Words in a defun
The lengths' list for `debug.el' takes less than a se
ond to produ
e and
looks like this:
(77 95 85 87 131 89 50 25 44 44 68 35 64 45 17 34 167 457)
(Using my old ma
hine, the version 19 lengths' list for `debug.el' took
seven se
onds to produ
e and looked like this:
(75 41 80 62 20 45 44 68 45 12 34 235)
(The newer version of `debug.el'
ontains more defuns than the earlier
one; and my new ma
hine is mu
h faster than the old one.)
Note that the length of the last denition in the le is rst in the list.
;;; true-or-false-test
(while list-of-files
(setq lengths-list
(append
lengths-list
whi
h
onstru
ts a new list in whi
h the rst argument to
ons be
omes the
rst element of the new list:
((1 2 3 4) 5 6 7 8)
(lengths-list-file "./lisp/makesum.el")
) (85 181)
(re
ursive-lengths-list-many-files
'("./lisp/ma
ros.el"
"./lisp/mail/mailalias.el"
"./lisp/makesum.el"))
) (273 263 456 90 38 32 26 77 174 180 321 198 324 85 181)
The re
ursive-lengths-list-many-files fun
tion produ
es the out-
put we want.
The next step is to prepare the data in the list for display in a graph.
some property is true or false. The sort fun
tion will reorder a list a
ord-
ing to whatever property the predi
ate uses; this means that sort
an be
used to sort non-numeri
lists by non-numeri
riteria|it
an, for example,
alphabetize a list.
The < fun
tion is used when sorting a numeri
list. For example,
(sort '(4 8 21 17 33 7 21 7) '<)
produ
es this:
(4 7 7 8 17 21 21 33)
(Note that in this example, both the arguments are quoted so that the
symbols are not evaluated before being passed to sort as arguments.)
Sorting the list returned by the re
ursive-lengths-list-many-files
fun
tion is straightforward; it uses the < fun
tion:
(sort
(re
ursive-lengths-list-many-files
'("../lisp/ma
ros.el"
"../lisp/mailalias.el"
"../lisp/makesum.el"))
'<
whi
h produ
es:
(85 86 116 122 154 176 179 265)
(Note that in this example, the rst argument to sort is not quoted, sin
e
the expression must be evaluated so as to produ
e the list that is passed to
sort.)
fun
tion not only lists all the lenames in a dire
tory, in
luding the names
of sub-dire
tories, but also their attributes.
To restate our goal: to
reate a fun
tion that will enable us to feed
lenames to re
ursive-lengths-list-many-files as a list that looks like
this (but with more elements):
("../lisp/ma
ros.el"
"../lisp/mail/rmail.el"
"../lisp/makesum.el")
The dire
tory-files-and-attributes fun
tion returns a list of lists.
Ea
h of the lists within the main list
onsists of 13 elements. The rst
element is a string that
ontains the name of the le { whi
h, in GNU/Linux,
may be a `dire
tory le', that is to say, a le with the spe
ial attributes of
a dire
tory. The se
ond element of the list is t for a dire
tory, a string for
symboli
link (the string is the name linked to), or nil.
For example, the rst `.el' le in the `lisp/' dire
tory is `abbrev.el'.
Its name is `/usr/lo
al/share/ema
s/21.0.100/lisp/abbrev.el' and it
is not a dire
tory or a symboli
link.
This is how dire
tory-files-and-attributes lists that le and its
attributes:
("/usr/lo
al/share/ema
s/21.0.100/lisp/abbrev.el"
nil
1
1000
100
(15019 32380)
(14883 48041)
(15214 49336)
11583
"-rw-rw-r--"
t
341385
776)
On the other hand, `mail/' is a dire
tory within the `lisp/' dire
tory.
The beginning of its listing looks like this:
("/usr/lo
al/share/ema
s/21.0.100/lisp/mail"
t
...
)
(Look at the do
umentation of file-attributes to learn about the dif-
ferent attributes. Bear in mind that the file-attributes fun
tion does not
list the lename, so its rst element is dire
tory-files-and-attributes's
se
ond element.)
196 Chapter 14: Counting Words in a defun
We will want our new fun
tion, files-in-below-dire
tory, to list the
`.el' les in the dire
tory it is told to
he
k, and in any dire
tories below
that dire
tory.
This gives us a hint on how to
onstru
t files-in-below-dire
tory:
within a dire
tory, the fun
tion should add `.el' lenames to a list; and if,
within a dire
tory, the fun
tion
omes upon a sub-dire
tory, it should go
into that sub-dire
tory and repeat its a
tions.
However, we should note that every dire
tory
ontains a name that refers
to itself,
alled `.', (\dot") and a name that refers to its parent dire
tory,
alled `..' (\double dot"). (In `/', the root dire
tory, `..' refers to itself,
sin
e `/' has no parent.) Clearly, we do not want our files-in-below-
dire
tory fun
tion to enter those dire
tories, sin
e they always lead us,
dire
tly or indire
tly, to the
urrent dire
tory.
Consequently, our files-in-below-dire
tory fun
tion must do several
tasks:
Che
k to see whether it is looking at a lename that ends in `.el'; and
if so, add its name to a list.
Che
k to see whether it is looking at a lename that is the name of a
dire
tory; and if so,
Che
k to see whether it is looking at `.' or `..'; and if so skip it.
Or else, go into that dire
tory and repeat the pro
ess.
Let's write a fun
tion denition to do these tasks. We will use a while
loop to move from one lename to another within a dire
tory,
he
king what
needs to be done; and we will use a re
ursive
all to repeat the a
tions on
ea
h sub-dire
tory. The re
ursive pattern is `a
umulate' (see \Re
ursive
Pattern: a
umulate ", page 142), using append as the
ombiner.
Here is the fun
tion:
(defun files-in-below-dire
tory (dire
tory)
"List the .el files in DIRECTORY and in its sub-dire
tories."
;; Although the fun
tion will be used non-intera
tively,
;; it will be easier to test if we make it intera
tive.
;; The dire
tory will have a name su
h as
;; "/usr/lo
al/share/ema
s/21.0.100/lisp/"
(intera
tive "DDire
tory name: ")
(let (el-files-list
(
urrent-dire
tory-list
(dire
tory-files-and-attributes dire
tory t)))
;; while we are in the
urrent dire
tory
(while
urrent-dire
tory-list
Counting fun
tion denitions 197
(
ond
;;
he
k to see whether filename ends in `.el'
;; and if so, append its name to a list.
((equal ".el" (substring (
ar (
ar
urrent-dire
tory-list)) -3))
(setq el-files-list
(
ons (
ar (
ar
urrent-dire
tory-list)) el-files-list)))
;;
he
k whether filename is that of a dire
tory
((eq t (
ar (
dr (
ar
urrent-dire
tory-list))))
;; de
ide whether to skip or re
urse
(if
(equal (or "." "..")
(substring (
ar (
ar
urrent-dire
tory-list)) -1))
;; then do nothing if filename is that of
;;
urrent dire
tory or parent
()
;; else des
end into the dire
tory and repeat the pro
ess
(setq el-files-list
(append
(files-in-below-dire
tory
(
ar (
ar
urrent-dire
tory-list)))
el-files-list)))))
;; move to the next filename in the list; this also
;; shortens the list so the while loop eventually
omes to an end
(setq
urrent-dire
tory-list (
dr
urrent-dire
tory-list)))
;; return the filenames
el-files-list))
The files-in-below-dire
tory dire
tory-files fun
tion takes one
argument, the name of a dire
tory.
Thus, on my system,
(length
(files-in-below-dire
tory "/usr/lo
al/share/ema
s/21.0.100/lisp/"))
tells me that my version 21.0.100 Lisp sour
es dire
tory
ontains 754 `.el'
les.
files-in-below-dire
tory returns a list in reverse alphabeti
al order.
An expression to sort the list in alphabeti
al order looks like this:
(sort
(files-in-below-dire
tory "/usr/lo
al/share/ema
s/21.0.100/lisp/")
'string-lessp)
between 10 and 19 words and symbols, how many
ontain between 20 and
29 words and symbols, and so on.
With a sorted list of numbers, this is easy:
ount how many elements
of the list are smaller than 10, then, after moving past the numbers just
ounted,
ount how many are smaller than 20, then, after moving past the
numbers just
ounted,
ount how many are smaller than 30, and so on. Ea
h
of the numbers, 10, 20, 30, 40, and the like, is one larger than the top of
that range. We
an
all the list of su
h numbers the top-of-ranges list.
If we wished, we
ould generate this list automati
ally, but it is simpler
to write a list manually. Here it is:
(defvar top-of-ranges
'(10 20 30 40 50
60 70 80 90 100
110 120 130 140 150
160 170 180 190 200
210 220 230 240 250
260 270 280 290 300)
"List spe
ifying ranges for `defuns-per-range'.")
The fun
tion is straightforward ex
ept for one subtle feature. The true-or-
false test of the inner loop looks like this:
(and (
ar sorted-lengths)
(< (
ar sorted-lengths) top-of-range))
The purpose of the test is to determine whether the rst item in the
sorted-lengths list is less than the value of the top of the range.
The simple version of the test works ne unless the sorted-lengths
list has a nil value. In that
ase, the (
ar sorted-lengths) expression
fun
tion returns nil. The < fun
tion
annot
ompare a number to nil,
whi
h is an empty list, so Ema
s signals an error and stops the fun
tion
from attempting to
ontinue to exe
ute.
The sorted-lengths list always be
omes nil when the
ounter rea
hes
the end of the list. This means that any attempt to use the defuns-per-
range fun
tion with the simple version of the test will fail.
We solve the problem by using the (
ar sorted-lengths) expression in
onjun
tion with the and expression. The (
ar sorted-lengths) expres-
sion returns a non-nil value so long as the list has at least one number within
it, but returns nil if the list is empty. The and expression rst evaluates
the (
ar sorted-lengths) expression, and if it is nil, returns false without
evaluating the < expression. But if the (
ar sorted-lengths) expression
returns a non-nil value, the and expression evaluates the < expression, and
returns that value as the value of the and expression.
This way, we avoid an error. See Se
tion 12.4, \forward-paragraph: a
Goldmine of Fun
tions", page 155, for more information about and.
Here is a short test of the defuns-per-range fun
tion. First, evaluate
the expression that binds (a shortened) top-of-ranges list to the list of
values, then evaluate the expression for binding the sorted-lengths list,
and then evaluate the defuns-per-range fun
tion.
;; (Shorter list than we will use later.)
(setq top-of-ranges
'(110 120 130 140 150
160 170 180 190 200))
(setq sorted-lengths
'(85 86 110 116 122 129 154 176 179 200 265 300 300))
15 Readying a Graph
Our goal is to
onstru
t a graph showing the numbers of fun
tion deni-
tions of various lengths in the Ema
s lisp sour
es.
As a pra
ti
al matter, if you were
reating a graph, you would probably
use a program su
h as gnuplot to do the job. (gnuplot is ni
ely integrated
into GNU Ema
s.) In this
ase, however, we
reate one from s
rat
h, and
in the pro
ess we will re-a
quaint ourselves with some of what we learned
before and learn more.
In this
hapter, we will rst write a simple graph printing fun
tion. This
rst denition will be a prototype, a rapidly written fun
tion that enables
us to re
onnoiter this unknown graph-making territory. We will dis
over
dragons, or nd that they are myth. After s
outing the terrain, we will feel
more
ondent and enhan
e the fun
tion to label the axes automati
ally.
Sin
e Ema
s is designed to be
exible and work with all kinds of terminals,
in
luding
hara
ter-only terminals, the graph will need to be made from one
of the `typewriter' symbols. An asterisk will do; as we enhan
e the graph-
printing fun
tion, we
an make the
hoi
e of symbol a user option.
We
an
all this fun
tion graph-body-print; it will take a numbers-list
as its only argument. At this stage, we will not label the graph, but only
print its body.
The graph-body-print fun
tion inserts a verti
al
olumn of asterisks for
ea
h element in the numbers-list. The height of ea
h line is determined by
the value of that element of the numbers-list.
Inserting
olumns is a repetitive a
t; that means that this fun
tion
an
be written either with a while loop or re
ursively.
Our rst
hallenge is to dis
over how to print a
olumn of asterisks.
Usually, in Ema
s, we print
hara
ters onto a s
reen horizontally, line by
line, by typing. We have two routes we
an follow: write our own
olumn-
insertion fun
tion or dis
over whether one exists in Ema
s.
To see whether there is one in Ema
s, we
an use the M-x apropos
om-
mand. This
ommand is like the C-h a (
ommand-apropos)
ommand, ex-
ept that the latter nds only those fun
tions that are
ommands. The
M-x apropos
ommand lists all symbols that mat
h a regular expression,
in
luding fun
tions that are not intera
tive.
What we want to look for is some
ommand that prints or inserts
olumns.
Very likely, the name of the fun
tion will
ontain either the word `print' or
the word `insert' or the word `
olumn'. Therefore, we
an simply type M-x
apropos RET print\|insert\|
olumn RET and look at the result. On my
system, this
ommand takes quite some time, and then produ
es a list of
79 fun
tions and variables. S
anning down the list, the only fun
tion that
looks as if it might do the job is insert-re
tangle.
204 Chapter 15: Readying a Graph
number of lines above the base for the graph to print
orre
tly. This
ould
be diÆ
ult.
Alternatively, if we
an gure out some way to pass insert-re
tangle
a list of the same length ea
h time, then we
an pla
e point on the same line
ea
h time, but move it over one
olumn to the right for ea
h new
olumn.
If we do this, however, some of the entries in the list passed to insert-
re
tangle must be blanks rather than asterisks. For example, if the max-
imum height of the graph is 5, but the height of the
olumn is 3, then
insert-re
tangle requires an argument that looks like this:
(" " " " "*" "*" "*")
This last proposal is not so diÆ
ult, so long as we
an determine the
olumn height. There are two ways for us to spe
ify the
olumn height:
we
an arbitrarily state what it will be, whi
h would work ne for graphs
of that height; or we
an sear
h through the list of numbers and use the
maximum height of the list as the maximum height of the graph. If the
latter operation were diÆ
ult, then the former pro
edure would be easiest,
but there is a fun
tion built into Ema
s that determines the maximum of
its arguments. We
an use that fun
tion. The fun
tion is
alled max and it
returns the largest of all its arguments, whi
h must be numbers. Thus, for
example,
(max 3 4 6 5 7 3)
returns 7. (A
orresponding fun
tion
alled min returns the smallest of all
its arguments.)
However, we
annot simply
all max on the numbers-list; the max fun
-
tion expe
ts numbers as its argument, not a list of numbers. Thus, the
following expression,
(max '(3 4 6 5 7 3))
produ
es the following error message;
Wrong type of argument: number-or-marker-p, (3 4 6 5 7 3)
We need a fun
tion that passes a list of arguments to a fun
tion. This
fun
tion is apply. This fun
tion `applies' its rst argument (a fun
tion) to
its remaining arguments, the last of whi
h may be a list.
For example,
(apply 'max 3 4 7 3 '(4 8 5))
returns 8.
(In
identally, I don't know how you would learn of this fun
tion without
a book su
h as this. It is possible to dis
over other fun
tions, like sear
h-
forward or insert-re
tangle, by guessing at a part of their names and
then using apropos. Even though its base in metaphor is
lear|`apply'
its rst argument to the rest|I doubt a novi
e would
ome up with that
parti
ular word when using apropos or other aid. Of
ourse, I
ould be
wrong; after all, the fun
tion was rst named by someone who had to invent
it.)
206 Chapter 15: Readying a Graph
If you install this fun
tion and then evaluate the following expression you
will see that it returns the list as desired:
(
olumn-of-graph 5 3)
Readying a Graph 207
returns
(" " " " "*" "*" "*")
;; Fill in graph-blanks.
(while (> number-of-top-blanks 0)
(setq insert-list (
ons graph-blank insert-list))
(setq number-of-top-blanks
(1- number-of-top-blanks)))
The one unexpe
ted expression in this fun
tion is the (sit-for 0) expres-
sion in the while loop. This expression makes the graph printing operation
more interesting to wat
h than it would be otherwise. The expression
auses
Ema
s to `sit' or do nothing for a zero length of time and then redraw the
s
reen. Pla
ed here, it
auses Ema
s to redraw the s
reen
olumn by
olumn.
Without it, Ema
s would not redraw the s
reen until the fun
tion exits.
We
an test graph-body-print with a short list of numbers.
1. Install graph-symbol, graph-blank,
olumn-of-graph, whi
h are in
Chapter 15, \Readying a Graph", page 203, and graph-body-print.
2. Copy the following expression:
(graph-body-print '(1 2 3 4 6 4 3 5 7 6 5 2 3))
3. Swit
h to the `*s
rat
h*' buer and pla
e the
ursor where you want
the graph to start.
4. Type M-: (eval-expression).
5. Yank the graph-body-print expression into the minibuer with C-y
(yank).
6. Press hRETi to evaluate the graph-body-print expression.
Ema
s will print a graph like this:
*
* **
* ****
*** ****
********* *
************
*************
Here is the rst part of this `.ema
s' le that does something besides
remind a forgetful human!
The rst of the two lines in parentheses tells Ema
s to turn on Text mode
when you nd a le, unless that le should go into some other mode, su
h
as C mode.
When Ema
s reads a le, it looks at the extension to the le name, if
any. (The extension is the part that
omes after a `.'.) If the le ends with
a `.
' or `.h' extension then Ema
s turns on C mode. Also, Ema
s looks at
rst nonblank line of the le; if the line says `-*- C -*-', Ema
s turns on
C mode. Ema
s possesses a list of extensions and spe
i
ations that it uses
automati
ally. In addition, Ema
s looks near the last page for a per-buer,
\lo
al variables list", if any.
See se
tions \How Major Modes are Chosen" and \Lo
al Variables in
Files" in The GNU Ema
s Manual.
Now, ba
k to the `.ema
s' le.
Here is the line again; how does it work?
(setq default-major-mode 'text-mode)
This line is a short, but
omplete Ema
s Lisp expression.
We are already familiar with setq. It sets the following variable,
default-major-mode, to the subsequent value, whi
h is text-mode. The
single quote mark before text-mode tells Ema
s to deal dire
tly with the
text-mode variable, not with whatever it might stand for. See Se
tion 1.9,
\Setting the Value of a Variable", page 17, for a reminder of how setq works.
The main point is that there is no dieren
e between the pro
edure you use
to set a value in your `.ema
s' le and the pro
edure you use anywhere else
in Ema
s.
Here are the next two lines:
(add-hook 'text-mode-hook 'text-mode-hook-identify)
(add-hook 'text-mode-hook 'turn-on-auto-fill)
In these two lines, the add-hook
ommand rst adds text-mode-hook-
identify to the variable
alled text-mode-hook and then adds turn-on-
auto-fill to the variable.
turn-on-auto-fill is the name of a program, that, you guessed it!,
turns on Auto Fill mode. text-mode-hook-identify is a fun
tion that
tells toggle-text-mode-auto-fill whi
h buers are in Text mode.
Every time Ema
s turns on Text mode, Ema
s runs the
ommands
`hooked' onto Text mode. So every time Ema
s turns on Text mode, Ema
s
also turns on Auto Fill mode.
In brief, the rst line
auses Ema
s to enter Text mode when you edit
a le, unless the le name extension, rst non-blank line, or lo
al variables
tell Ema
s otherwise.
Text mode among other a
tions, sets the syntax table to work
onve-
niently for writers. In Text mode, Ema
s
onsiders an apostrophe as part
Indent Tabs Mode 219
of a word like a letter; but Ema
s does not
onsider a period or a spa
e as
part of a word. Thus, M-f moves you over `it's'. On the other hand, in C
mode, M-f stops just after the `t' of `it's'.
The se
ond and third lines
auses Ema
s to turn on Auto Fill mode when
it turns on Text mode. In Auto Fill mode, Ema
s automati
ally breaks a
line that is too wide and brings the ex
essively wide part of the line down
to the next line. Ema
s breaks lines between words, not within them.
When Auto Fill mode is turned o, lines
ontinue to the right as you
type them. Depending on how you set the value of trun
ate-lines, the
words you type either disappear o the right side of the s
reen, or else are
shown, in a rather ugly and unreadable manner, as a
ontinuation line on
the s
reen.
In addition, in this part of my `.ema
s' le, I tell the Ema
s ll
ommands
to insert two spa
es after a
olon:
(setq
olon-double-spa
e t)
(setq mail-aliases t)
This setq
ommand sets the value of the variable mail-aliases to t. Sin
e
t means true, the line says, in ee
t, \Yes, use mail aliases."
Mail aliases are
onvenient short names for long email addresses or for
lists of email addresses. The le where you keep your `aliases' is `~/.mailr
'.
You write an alias like this:
alias geo georgefoobar.wiz.edu
When you write a message to George, address it to `geo'; the mailer will
automati
ally expand `geo' to the full address.
16.8 Keymaps
Ema
s uses keymaps to re
ord whi
h keys
all whi
h
ommands. When
you use global-set-key to set the keybinding for a single
ommand in all
parts of Ema
s, you are spe
ifying the keybinding in
urrent-global-map.
Spe
i
modes, su
h as C mode or Text mode, have their own keymaps;
the mode-spe
i
keymaps override the global map that is shared by all
buers.
The global-set-key fun
tion binds, or rebinds, the global keymap. For
example, the following binds the key C-x C-b to the fun
tion buffer-menu:
(global-set-key "\C-x\C-b" 'buffer-menu)
Mode-spe
i
keymaps are bound using the define-key fun
tion, whi
h
takes a spe
i
keymap as an argument, as well as the key and the
ommand.
For example, my `.ema
s' le
ontains the following expression to bind the
texinfo-insert-group
ommand to C-
C-
g:
(define-key texinfo-mode-map "\C-
\C-
g" 'texinfo-insert-group)
The texinfo-insert-group fun
tion itself is a little extension to Texinfo
mode that inserts `group' into a Texinfo le. I use this
ommand all the
time and prefer to type the three strokes C-
C-
g rather than the six
strokes g r o u p. (`group' and its mat
hing `end group' are
ommands
222 Chapter 16: Your `.ema
s' File
that keep all en
losed text together on one page; many multi-line examples
in this book are surrounded by `group ... end group'.)
Here is the texinfo-insert-group fun
tion denition:
(defun texinfo-insert-group ()
"Insert the string group in a Texinfo buffer."
(intera
tive)
(beginning-of-line)
(insert "group\n"))
(Of
ourse, I
ould have used Abbrev mode to save typing, rather than
write a fun
tion to insert a word; but I prefer key strokes
onsistent with
other Texinfo mode key bindings.)
You will see numerous define-key expressions in `loaddefs.el' as well
as in the various mode libraries, su
h as `
-mode.el' and `lisp-mode.el'.
See se
tion \Customizing Key Bindings" in The GNU Ema
s Manual,
and se
tion \Keymaps" in The GNU Ema
s Lisp Referen
e Manual, for
more information about keymaps.
16.10 Autoloading
Instead of installing a fun
tion by loading the le that
ontains it, or by
evaluating the fun
tion denition, you
an make the fun
tion available but
not a
tually install it until it is rst
alled. This is
alled autoloading.
When you exe
ute an autoloaded fun
tion, Ema
s automati
ally evalu-
ates the le that
ontains the denition, and then
alls the fun
tion.
Ema
s starts qui
ker with autoloaded fun
tions, sin
e their libraries are
not loaded right away; but you need to wait a moment when you rst use
su
h a fun
tion, while its
ontaining le is evaluated.
Rarely used fun
tions are frequently autoloaded. The `loaddefs.el' li-
brary
ontains hundreds of autoloaded fun
tions, from bookmark-set to
wordstar-mode. Of
ourse, you may
ome to use a `rare' fun
tion frequently.
224 Chapter 16: Your `.ema
s' File
When you do, you should load that fun
tion's le with a load expression in
your `.ema
s' le.
In my `.ema
s' le for Ema
s version 21, I load 12 libraries that
ontain
fun
tions that would otherwise be autoloaded. (A
tually, it would have been
better to in
lude these les in my `dumped' Ema
s when I built it, but I
forgot. See se
tion \Building Ema
s" in The GNU Ema
s Lisp Referen
e
Manual, and the `INSTALL' le for more about dumping.)
You may also want to in
lude autoloaded expressions in your `.ema
s'
le. autoload is a built-in fun
tion that takes up to ve arguments, the nal
three of whi
h are optional. The rst argument is the name of the fun
tion
to be autoloaded; the se
ond is the name of the le to be loaded. The third
argument is do
umentation for the fun
tion, and the fourth tells whether
the fun
tion
an be
alled intera
tively. The fth argument tells what type
of obje
t|autoload
an handle a keymap or ma
ro as well as a fun
tion
(the default is a fun
tion).
Here is a typi
al example:
(autoload 'html-helper-mode
"html-helper-mode" "Edit HTML do
uments" t)
2 When I start instan
es of Ema
s that do not load my `.ema
s' le or any site le, I
also turn o blinking:
ema
s -q --no-site-file -eval '(blink-
ursor-mode nil)'
226 Chapter 16: Your `.ema
s' File
;; Set a Mode Line that tells me whi
h ma
hine, whi
h dire
tory,
;; and whi
h line I am on, plus the other
ustomary information.
(setq default-mode-line-format
(quote
(#("-" 0 1
(help-e
ho
"mouse-1: sele
t window, mouse-2: delete others ..."))
mode-line-mule-info
mode-line-modified
mode-line-frame-identifi
ation
" "
mode-line-buffer-identifi
ation
" "
(:eval (substring
(system-name) 0 (string-mat
h "\\..+" (system-name))))
":"
default-dire
tory
#(" " 0 1
(help-e
ho
"mouse-1: sele
t window, mouse-2: delete others ..."))
(line-number-mode " Line %l ")
global-mode-string
A Modied Mode Line 229
#(" %[(" 0 6
(help-e
ho
"mouse-1: sele
t window, mouse-2: delete others ..."))
(:eval (mode-line-mode-name))
mode-line-pro
ess
minor-mode-alist
#("%n" 0 2 (help-e
ho "mouse-2: widen" lo
al-map (keymap ...)))
")%℄ "
(-3 . "%P")
;; "-%-"
)))
Here, I redene the default mode line. Most of the parts are from the original;
but I make a few
hanges. I set the default mode line format so as to permit
various modes, su
h as Info, to override it.
Many elements in the list are self-explanatory: mode-line-modified is
a variable that tells whether the buer has been modied, mode-name tells
the name of the mode, and so on. However, the format looks
ompli
ated
be
ause of two features we have not dis
ussed.
The rst string in the mode line is a dash or hyphen, `-'. In the old days,
it would have been spe
ied simply as "-". But nowadays, Ema
s
an add
properties to a string, su
h as highlighting or, as in this
ase, a help feature.
If you pla
e your mouse
ursor over the hyphen, some help information ap-
pears (By default, you must wait one se
ond before the information appears.
You
an
hange that timing by
hanging the value of tooltip-delay.)
The new string format has a spe
ial syntax:
#("-" 0 1 (help-e
ho "mouse-1: sele
t window, ..."))
The #( begins a list. The rst element of the list is the string itself, just one
`-'. The se
ond and third elements spe
ify the range over whi
h the fourth
element applies. A range starts after a
hara
ter, so a zero means the range
starts just before the rst
hara
ter; a 1 means that the range ends just
after the rst
hara
ter. The third element is the property for the range.
It
onsists of a property list, a property name, in this
ase, `help-e
ho',
followed by a value, in this
ase, a string. The se
ond, third, and fourth
elements of this new string format
an be repeated.
See se
tion \Text Properties in String" in The GNU Ema
s Lisp Refer-
en
e Manual, and see se
tion \Mode Line Format" in The GNU Ema
s Lisp
Referen
e Manual, for more information.
mode-line-buffer-identifi
ation displays the
urrent buer name.
It is a list beginning (#("%12b" 0 4 .... The #( begins the list.
The `"%12b"' displays the
urrent buer name, using the buffer-name
fun
tion with whi
h we are familiar; the `12' spe
ies the maximum number
of
hara
ters that will be displayed. When a name has fewer
hara
ters,
whitespa
e is added to ll out to this number. (Buer names
an and often
230 Chapter 16: Your `.ema
s' File
should be longer than 12
hara
ters; this length works well in a typi
al 80
olumn wide window.)
:eval is a new feature in GNU Ema
s version 21. It says to evaluate
the following form and use the result as a string to display. In this
ase, the
expression displays the rst
omponent of the full system name. The end of
the rst
omponent is a `.' (`period'), so I use the string-mat
h fun
tion
to tell me the length of the rst
omponent. The substring from the zeroth
hara
ter to that length is the name of the ma
hine.
This is the expression:
(:eval (substring
(system-name) 0 (string-mat
h "\\..+" (system-name))))
`%[' and `%℄'
ause a pair of square bra
kets to appear for ea
h re
ursive
editing level. `%n' says `Narrow' when narrowing is in ee
t. `%P' tells you
the per
entage of the buer that is above the bottom of the window, or
`Top', `Bottom', or `All'. (A lower
ase `p' tell you the per
entage above the
top of the window.) `%-' inserts enough dashes to ll out the line.
Remember, \You don't have to like Ema
s to like it" | your own Ema
s
an have dierent
olors, dierent
ommands, and dierent keys than a
default Ema
s.
On the other hand, if you want to bring up a plain `out of the box' Ema
s,
with no
ustomization, type:
ema
s -q
This will start an Ema
s that does not load your `~/.ema
s' initialization
le. A plain, default Ema
s. Nothing more.
debug 231
17 Debugging
GNU Ema
s has two debuggers, debug and edebug. The rst is built
into the internals of Ema
s and is always with you; the se
ond requires that
you instrument a fun
tion before you
an use it.
Both debuggers are des
ribed extensively in se
tion \Debugging Lisp Pro-
grams" in The GNU Ema
s Lisp Referen
e Manual. In this
hapter, I will
walk through a short example of ea
h.
17.1 debug
Suppose you have written a fun
tion denition that is intended to return
the sum of the numbers 1 through a given number. (This is the triangle
fun
tion dis
ussed earlier. See \Example with De
rementing Counter",
page 129, for a dis
ussion.)
However, your fun
tion denition has a bug. You have mistyped `1=' for
`1-'. Here is the broken denition:
(defun triangle-bugged (number)
"Return sum of numbers 1 through NUMBER in
lusive."
(let ((total 0))
(while (> number 0)
(setq total (+ total number))
(setq number (1= number))) ; Error here.
total))
If you are reading this in Info, you
an evaluate this denition in the
normal fashion. You will see triangle-bugged appear in the e
ho area.
Now evaluate the triangle-bugged fun
tion with an argument of 4:
(triangle-bugged 4)
In GNU Ema
s version 21, you will
reate and enter a `*Ba
ktra
e*' buer
that says:
---------- Buffer: *Ba
ktra
e* ----------
Debugger entered--Lisp error: (void-fun
tion 1=)
(1= number)
(setq number (1= number))
(while (> number 0) (setq total (+ total number))
(setq number (1= number)))
(let ((total 0)) (while (> number 0) (setq total ...)
(setq number ...)) total)
triangle-bugged(4)
232 Chapter 17: Debugging
eval((triangle-bugged 4))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
all-intera
tively(eval-last-sexp)
---------- Buffer: *Ba
ktra
e* ----------
(I have reformatted this example slightly; the debugger does not fold long
lines. As usual, you
an quit the debugger by typing q in the `*Ba
ktra
e*'
buer.)
In pra
ti
e, for a bug as simple as this, the `Lisp error' line will tell you
what you need to know to
orre
t the denition. The fun
tion 1= is `void'.
In GNU Ema
s 20 and before, you will see:
Symbol's fun
tion definition is void: 1=
whi
h has the same meaning as the `*Ba
ktra
e*' buer line in version 21.
However, suppose you are not quite
ertain what is going on? You
an
read the
omplete ba
ktra
e.
In this
ase, you need to run GNU Ema
s 21, whi
h automati
ally starts
the debugger that puts you in the `*Ba
ktra
e*' buer; or else, you need to
start the debugger manually as des
ribed below.
Read the `*Ba
ktra
e*' buer from the bottom up; it tells you what
Ema
s did that led to the error. Ema
s made an intera
tive
all to C-x C-
e (eval-last-sexp), whi
h led to the evaluation of the triangle-bugged
expression. Ea
h line above tells you what the Lisp interpreter evaluated
next.
The third line from the top of the buer is
(setq number (1= number))
Ema
s tried to evaluate this expression; in order to do so, it tried to evaluate
the inner expression shown on the se
ond line from the top:
(1= number)
This is where the error o
urred; as the top line says:
Debugger entered--Lisp error: (void-fun
tion 1=)
You
an
orre
t the mistake, re-evaluate the fun
tion denition, and then
run your test again.
17.2 debug-on-entry
GNU Ema
s 21 starts the debugger automati
ally when your fun
tion
has an error. GNU Ema
s version 20 and before did not; it simply presented
you with an error message. You had to start the debugger manually.
You
an start the debugger manually for all versions of Ema
s; the ad-
vantage is that the debugger runs even if you do not have a bug in your
ode. Sometimes your
ode will be free of bugs!
debug-on-entry 233
You
an enter the debugger when you
all the fun
tion by
alling debug-
on-entry.
Type:
M-x debug-on-entry RET triangle-bugged RET
Now, evaluate the following:
(triangle-bugged 5)
All versions of Ema
s will
reate a `*Ba
ktra
e*' buer and tell you that it
is beginning to evaluate the triangle-bugged fun
tion:
---------- Buffer: *Ba
ktra
e* ----------
Debugger entered--entering a fun
tion:
* triangle-bugged(5)
eval((triangle-bugged 5))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
all-intera
tively(eval-last-sexp)
---------- Buffer: *Ba
ktra
e* ----------
In the `*Ba
ktra
e*' buer, type d. Ema
s will evaluate the rst expres-
sion in triangle-bugged; the buer will look like this:
---------- Buffer: *Ba
ktra
e* ----------
Debugger entered--beginning evaluation of fun
tion
all form:
* (let ((total 0)) (while (> number 0) (setq total ...)
(setq number ...)) total)
* triangle-bugged(5)
eval((triangle-bugged 5))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
all-intera
tively(eval-last-sexp)
---------- Buffer: *Ba
ktra
e* ----------
Now, type d again, eight times, slowly. Ea
h time you type d, Ema
s will
evaluate another expression in the fun
tion denition.
234 Chapter 17: Debugging
Finally, after you type d two more times, Ema
s will rea
h the error, and
the top two lines of the `*Ba
ktra
e*' buer will look like this:
---------- Buffer: *Ba
ktra
e* ----------
Debugger entered--Lisp error: (void-fun
tion 1=)
* (1= number)
...
---------- Buffer: *Ba
ktra
e* ----------
Or, you
an insert a line that says (debug) into your
ode where you
want the debugger to start, like this:
(defun triangle-bugged (number)
"Return sum of numbers 1 through NUMBER in
lusive."
(let ((total 0))
(while (> number 0)
(setq total (+ total number))
(debug) ; Start debugger.
(setq number (1= number))) ; Error here.
total))
The debug fun
tion is des
ribed in detail in se
tion \The Lisp Debugger"
in The GNU Ema
s Lisp Referen
e Manual.
Normally, you would install this denition by positioning your
ursor after
the fun
tion's
losing parenthesis and typing C-x C-e (eval-last-sexp) or
else by positioning your
ursor within the denition and typing C-M-x (eval-
defun). (By default, the eval-defun
ommand works only in Ema
s Lisp
mode or in Lisp Intera
tive mode.)
236 Chapter 17: Debugging
However, to prepare this fun
tion denition for Edebug, you must rst
instrument the
ode using a dierent
ommand. You
an do this by posi-
tioning your
ursor within the denition and typing
M-x edebug-defun RET
This will
ause Ema
s to load Edebug automati
ally if it is not already
loaded, and properly instrument the fun
tion.
After instrumenting the fun
tion, pla
e your
ursor after the following
expression and type C-x C-e (eval-last-sexp):
(triangle-re
ursively-bugged 3)
You will be jumped ba
k to the sour
e for triangle-re
ursively-bugged
and the
ursor positioned at the beginning of the if line of the fun
tion.
Also, you will see an arrowhead at the left hand side of that line. The
arrowhead marks the line where the fun
tion is exe
uting. (In the following
examples, we show the arrowhead with `=>'; in a windowing system, you
may see the arrowhead as a solid triangle in the window `fringe'.)
=>?(if (= number 1)
In the example, the lo
ation of point is displayed with a star, `?' (in Info, it
is displayed as `-!-').
If you now press hSPCi, point will move to the next expression to be
exe
uted; the line will look like this:
=>(if ?(= number 1)
As you
ontinue to press hSPCi, point will move from expression to expression.
At the same time, whenever an expression returns a value, that value will be
displayed in the e
ho area. For example, after you move point past number,
you will see the following:
Result: 3 = C-
This means the value of number is 3, whi
h is as
ii `
ontrol-
' (the third
letter of the alphabet).
You
an
ontinue moving through the
ode until you rea
h the line with
the error. Before evaluation, that line looks like this:
=> ?(1= number))))) ; Error here.
When you press hSPCi on
e again, you will produ
e an error message that
says:
Symbol's fun
tion definition is void: 1=
This is the bug.
Press q to quit Edebug.
To remove instrumentation from a fun
tion denition, simply re-evaluate
it with a
ommand that does not instrument it. For example, you
ould
pla
e your
ursor after the denition's
losing parenthesis and type C-x C-e.
Edebug does a great deal more than walk with you through a fun
tion.
You
an set it so it ra
es through on its own, stopping only at an error or at
spe
ied stopping points; you
an
ause it to display the
hanging values of
Debugging Exer
ises 237
various expressions; you
an nd out how many times a fun
tion is
alled,
and more.
Edebug is des
ribed in se
tion \Edebug" in The GNU Ema
s Lisp Ref-
eren
e Manual.
18 Con
lusion
We have now rea
hed the end of this Introdu
tion. You have now learned
enough about programming in Ema
s Lisp to set values, to write simple
`.ema
s' les for yourself and your friends, and write simple
ustomizations
and extensions to Ema
s.
This is a pla
e to stop. Or, if you wish, you
an now go onward, and
tea
h yourself.
You have learned some of the basi
nuts and bolts of programming. But
only some. There are a great many more bra
kets and hinges that are easy
to use that we have not tou
hed.
A path you
an follow right now lies among the sour
es to GNU Ema
s
and in The GNU Ema
s Lisp Referen
e Manual.
The Ema
s Lisp sour
es are an adventure. When you read the sour
es
and
ome a
ross a fun
tion or expression that is unfamiliar, you need to
gure out or nd out what it does.
Go to the Referen
e Manual. It is a thorough,
omplete, and fairly easy-
to-read des
ription of Ema
s Lisp. It is written not only for experts, but
for people who know what you know. (The Referen
e Manual
omes with
the standard GNU Ema
s distribution. Like this introdu
tion, it
omes as
a Texinfo sour
e le, so you
an read it on-line and as a typeset, printed
book.)
Go to the other on-line help that is part of GNU Ema
s: the on-line
do
umentation for all fun
tions, and find-tags, the program that takes
you to sour
es.
Here is an example of how I explore the sour
es. Be
ause of its name,
`simple.el' is the le I looked at rst, a long time ago. As it happens some
of the fun
tions in `simple.el' are
ompli
ated, or at least look
ompli
ated
at rst sight. The open-line fun
tion, for example, looks
ompli
ated.
You may want to walk through this fun
tion slowly, as we did with
the forward-senten
e fun
tion. (See Se
tion 12.3, \forward-senten
e",
page 151.) Or you may want to skip that fun
tion and look at another,
su
h as split-line. You don't need to read all the fun
tions. A
ording
to
ount-words-in-defun, the split-line fun
tion
ontains 27 words and
symbols.
Even though it is short, split-line
ontains four expressions we have
not studied: skip-
hars-forward, indent-to,
urrent-
olumn and `?\n'.
Consider the skip-
hars-forward fun
tion. (It is part of the fun
tion
denition for ba
k-to-indentation, whi
h is shown in Se
tion 3.11, \Re-
view", page 46.)
In GNU Ema
s, you
an nd out more about skip-
hars-forward by
typing C-h f (des
ribe-fun
tion) and the name of the fun
tion. This gives
you the fun
tion do
umentation.
240 Chapter 18: Con
lusion
You may be able to guess what is done by a well named fun
tion su
h as
indent-to; or you
an look it up, too. In
identally, the des
ribe-fun
tion
fun
tion itself is in `help.el'; it is one of those long, but de
ipherable fun
-
tions. You
an look up des
ribe-fun
tion using the C-h f
ommand!
In this instan
e, sin
e the
ode is Lisp, the `*Help*' buer
ontains the
name of the library
ontaining the fun
tion's sour
e. You
an put point over
the name of the library and press the RET key, whi
h in this situation is
bound to help-follow, and be taken dire
tly to the sour
e, in the same way
as M-. (find-tag).
The denition for des
ribe-fun
tion illustrates how to
ustomize the
intera
tive expression without using the standard
hara
ter
odes; and it
shows how to
reate a temporary buer.
(The indent-to fun
tion is written in C rather than Ema
s Lisp; it is a
`built-in' fun
tion. help-follow only provides you with the do
umentation
of a built-in fun
tion; it does not take you to the sour
e. But find-tag will
take you to the sour
e, if properly set up.)
You
an look at a fun
tion's sour
e using find-tag, whi
h is bound to
M-. Finally, you
an nd out what the Referen
e Manual has to say by
visiting the manual in Info, and typing i (Info-index) and the name of the
fun
tion, or by looking up skip-
hars-forward in the index to a printed
opy of the manual.
Similarly, you
an nd out what is meant by `?\n'. You
an try using
Info-index with `?\n'. It turns out that this a
tion won't help; but don't
give up. If you sear
h the index for `\n' without the `?', you will be taken
dire
tly to the relevant se
tion of the manual. (See se
tion \Chara
ter Type"
in The GNU Ema
s Lisp Referen
e Manual. `?\n' stands for the newline
hara
ter.)
Other interesting sour
e les in
lude `paragraphs.el', `loaddefs.el',
and `loadup.el'. The `paragraphs.el' le in
ludes short, easily understood
fun
tions as well as longer ones. The `loaddefs.el' le
ontains the many
standard autoloads and many keymaps. I have never looked at it all; only at
parts. `loadup.el' is the le that loads the standard parts of Ema
s; it tells
you a great deal about how Ema
s is built. (See se
tion \Building Ema
s"
in The GNU Ema
s Lisp Referen
e Manual, for more about building.)
As I said, you have learned some nuts and bolts; however, and very
importantly, we have hardly tou
hed major aspe
ts of programming; I have
said nothing about how to sort information, ex
ept to use the predened
sort fun
tion; I have said nothing about how to store information, ex
ept
to use variables and lists; I have said nothing about how to write programs
that write programs. These are topi
s for another, and dierent kind of
book, a dierent kind of learning.
What you have done is learn enough for mu
h pra
ti
al work with GNU
Ema
s. What you have done is get started. This is the end of a beginning.
The the-the Fun
tion 241
The let expression de
lares a variable that will be only usable within
the bounds of this fun
tion. This variable is
alled length and is bound to
a value that is equal to the number of items in the kill ring. This is done
by using the fun
tion
alled length. (Note that this fun
tion has the same
name as the variable
alled length; but one use of the word is to name the
fun
tion and the other is to name the variable. The two are quite distin
t.
Similarly, an English speaker will distinguish between the meanings of the
word `ship' when he says: "I must ship this pa
kage immediately." and "I
must get aboard the ship immediately.")
The fun
tion length tells the number of items there are in a list, so
(length kill-ring) returns the number of items there are in the kill ring.
error. This is bad. Even though the
omputer takes the same steps as it
does when there is an `error', a term su
h as `
an
el' would have a
learer
onnotation.)
(setq kill-ring
("some text" "a different pie
e of text" "yet more text"))
246 Appendix B: Handling the Kill Ring
The variable length and the value of the expression (length kill-ring-
yank-pointer) will be the same sin
e the variable length is the length of
the kill ring and the kill-ring-yank-pointer is pointing to the whole kill
ring. Consequently, the value of
(- length (length kill-ring-yank-pointer))
will be zero. Sin
e the value of arg will be 1, this will mean that the value
of the whole expression
(+ arg (- length (length kill-ring-yank-pointer)))
will be 1.
Consequently, the argument to nth
dr will be found as the result of the
expression
(% 1 length)
So, in this
ode, if the value of length is 5, then the result of evaluating
(% 1 5)
is 1. (I just
he
ked this by pla
ing the
ursor after the expression and typing
C-x C-e. Indeed, 1 is printed in the e
ho area.)
Using % in rotate-yank-pointer
When the kill-ring-yank-pointer points to the beginning of the kill
ring, and the argument passed to rotate-yank-pointer is 1, the % expres-
sion returns 1:
(- length (length kill-ring-yank-pointer))
) 0
therefore,
(+ arg (- length (length kill-ring-yank-pointer)))
) 1
and
onsequently:
(% (+ arg (- length (length kill-ring-yank-pointer)))
length)
) 1
regardless of the value of length.
As a result of this, the setq kill-ring-yank-pointer expression simplies
to:
(setq kill-ring-yank-pointer (nth
dr 1 kill-ring))
What it does is now easy to understand. Instead of pointing as it did to the
rst element of the kill ring, the kill-ring-yank-pointer is set to point
to the se
ond element.
Clearly, if the argument passed to rotate-yank-pointer is two, then
the kill-ring-yank-pointer is set to (nth
dr 2 kill-ring); and so on
for dierent values of the argument.
Similarly, if the kill-ring-yank-pointer starts out pointing to the se
-
ond element of the kill ring, its length is shorter than the length of the kill
ring by 1, so the
omputation of the remainder is based on the expression
(% (+ arg 1) length). This means that the kill-ring-yank-pointer is
moved from the se
ond element of the kill ring to the third element if the
argument passed to rotate-yank-pointer is 1.
Let's see how this works by looking at the
ode, assuming the length of
the kill ring is 5 and the argument passed to rotate-yank-pointer is 1.
When the kill-ring-yank-pointer points to the last element of the kill
ring, its length is 1. The
ode looks like this:
(% (+ arg (- length (length kill-ring-yank-pointer))) length)
When the variables are repla
ed by their numeri
values, the expression
looks like this:
(% (+ 1 (- 5 1)) 5)
B.2 yank
After learning about rotate-yank-pointer, the
ode for the yank fun
-
tion is almost easy. It has only one tri
ky part, whi
h is the
omputation of
the argument to be passed to rotate-yank-pointer.
The
ode looks like this:
(defun yank (&optional arg)
"Reinsert the last stret
h of killed text.
More pre
isely, reinsert the stret
h of killed text most
re
ently killed OR yanked.
With just C-U as argument, same but put point in front
(and mark at end). With argument n, reinsert the nth
most re
ently killed stret
h of killed text.
See also the
ommand \\[yank-pop℄."
250 Appendix B: Handling the Kill Ring
front and mark at the end of the insertion. (The P argument to intera
tive
is designed to provide these values for the
ase when an optional argument
is not provided or when it is C-u.)
The then-part of the outer if expression handles the
ase when there is
no argument or when it is C-u. The else-part handles the other situations.
The else-part is itself another if expression.
The inner if expression tests whether the argument is a minus sign. (This
is done by pressing the hMETAi and - keys at the same time, or the hESCi
key and then the - key). In this
ase, the rotate-yank-pointer fun
tion
is passed -1 as an argument. This moves the kill-ring-yank-pointer
ba
kwards, whi
h is what is desired.
If the true-or-false-test of the inner if expression is false (that is, if the
argument is not a minus sign), the else-part of the expression is evaluated.
This is the expression (1- arg). Be
ause of the two if expressions, it will
only o
ur when the argument is a positive number or when it is a negative
number (not just a minus sign on its own). What (1- arg) does is de
rement
the number and return it. (The 1- fun
tion subtra
ts one from its argument.)
This means that if the argument to rotate-yank-pointer is 1, it is redu
ed
to zero, whi
h means the rst element to whi
h kill-ring-yank-pointer
points is yanked ba
k, as you would expe
t.
(nth
dr -1 animals)
) (
ats dogs elephants)
So, if a minus sign or a negative number is passed to yank, the kill-
ring-yank-point is rotated ba
kwards until it rea
hes the beginning of the
list. Then it stays there. Unlike the other
ase, when it jumps from the end
of the list to the beginning of the list, making a ring, it stops. This makes
sense. You often want to get ba
k to the most re
ently
lipped out pie
e of
text, but you don't usually want to insert text from as many as thirty kill
ommands ago. So you need to work through the ring to get to the end, but
won't
y
le around it inadvertently if you are trying to
ome ba
k to the
beginning.
In
identally, any number passed to yank with a minus sign pre
eding
it will be treated as 1. This is evidently a simpli
ation for writing the
program. You don't need to jump ba
k towards the beginning of the kill
ring more than one pla
e at a time and doing this is easier than writing a
fun
tion to determine the magnitude of the number that follows the minus
sign.
B.3 yank-pop
After understanding yank, the yank-pop fun
tion is easy. Leaving out
the do
umentation to save spa
e, it looks like this:
(defun yank-pop (arg)
(intera
tive "*p")
(if (not (eq last-
ommand 'yank))
(error "Previous
ommand was not a yank"))
(setq this-
ommand 'yank)
(let ((before (< (point) (mark))))
(delete-region (point) (mark))
(rotate-yank-pointer arg)
(set-mark (point))
(insert (
ar kill-ring-yank-pointer))
(if before (ex
hange-point-and-mark))))
The fun
tion is intera
tive with a small `p' so the prex argument is
pro
essed and passed to the fun
tion. The
ommand
an only be used after
a previous yank; otherwise an error message is sent. This
he
k uses the
variable last-
ommand whi
h is dis
ussed elsewhere. (See Se
tion 8.5, \
opy-
region-as-kill", page 102.)
The let
lause sets the variable before to true or false depending whether
point is before or after mark and then the region between point and mark
is deleted. This is the region that was just inserted by the previous yank
and it is this text that will be repla
ed. Next the kill-ring-yank-pointer
is rotated so that the previously inserted text is not reinserted yet again.
Mark is set at the beginning of the pla
e the new text will be inserted and
yank-pop 253
10 -
5 -
1 -
The fun
tion should be passed the height of the graph, and then should
onstru
t and insert the appropriate numbers and marks.
It is easy enough to see in the gure what the Y axis label should look
like; but to say in words, and then to write a fun
tion denition to do the
job is another matter. It is not quite true to say that we want a number
and a ti
every ve lines: there are only three lines between the `1' and the
`5' (lines 2, 3, and 4), but four lines between the `5' and the `10' (lines 6, 7,
8, and 9). It is better to say that we want a number and a ti
mark on the
base line (number 1) and then that we want a number and a ti
on the fth
line from the bottom and on every line that is a multiple of ve.
The next issue is what height the label should be? Suppose the maximum
height of tallest
olumn of the graph is seven. Should the highest label on
the Y axis be `5 -', and should the graph sti
k up above the label? Or should
the highest label be `7 -', and mark the peak of the graph? Or should the
highest label be 10 -, whi
h is a multiple of ve, and be higher than the
topmost value of the graph?
The latter form is preferred. Most graphs are drawn within re
tangles
whose sides are an integral number of steps long|5, 10, 15, and so on for a
step distan
e of ve. But as soon as we de
ide to use a step height for the ver-
ti
al axis, we dis
over that the simple expression in the varlist for
omputing
the height is wrong. The expression is (apply 'max numbers-list). This
returns the pre
ise height, not the maximum height plus whatever is ne
es-
sary to round up to the nearest multiple of ve. A more
omplex expression
is required.
As usual in
ases like this, a
omplex problem be
omes simpler if it is
divided into several smaller problems.
First,
onsider the
ase when the highest value of the graph is an integral
multiple of ve|when it is 5, 10, 15 ,or some higher multiple of ve. We
an use this value as the Y axis height.
A fairly simply way to determine whether a number is a multiple of ve
is to divide it by ve and see if the division results in a remainder. If there is
no remainder, the number is a multiple of ve. Thus, seven divided by ve
has a remainder of two, and seven is not an integral multiple of ve. Put in
slightly dierent language, more reminis
ent of the
lassroom, ve goes into
258 Appendix C: A Graph with Labelled Axes
seven on
e, with a remainder of two. However, ve goes into ten twi
e, with
no remainder: ten is an integral multiple of ve.
(% 10 5)
The rst expression returns 2 and the se
ond expression returns 0.
To test whether the returned value is zero or some other number, we
an
use the zerop fun
tion. This fun
tion returns t if its argument, whi
h must
be a number, is zero.
(zerop (% 7 5))
) nil
(zerop (% 10 5))
) t
Thus, the following expression will return t if the height of the graph is
evenly divisible by ve:
(zerop (% height 5))
(The value of height, of
ourse,
an be found from (apply 'max numbers-
list).)
On the other hand, if the value of height is not a multiple of ve, we want
to reset the value to the next higher multiple of ve. This is straightforward
arithmeti
using fun
tions with whi
h we are already familiar. First, we
divide the value of height by ve to determine how many times ve goes
into the number. Thus, ve goes into twelve twi
e. If we add one to this
quotient and multiply by ve, we will obtain the value of the next multiple
of ve that is larger than the height. Five goes into twelve twi
e. Add one
to two, and multiply by ve; the result is fteen, whi
h is the next multiple
of ve that is higher than twelve. The Lisp expression for this is:
(* (1+ (/ height 5)) 5)
For example, if you evaluate the following, the result is 15:
(* (1+ (/ 12 5)) 5)
Constru
t a Y Axis Element 259
All through this dis
ussion, we have been using `ve' as the value for
spa
ing labels on the Y axis; but we may want to use some other value. For
generality, we should repla
e `ve' with a variable to whi
h we
an assign
a value. The best name I
an think of for this variable is Y-axis-label-
spa
ing.
Using this term, and an if expression, we produ
e the following:
(if (zerop (% height Y-axis-label-spa
ing))
height
;; else
(* (1+ (/ height Y-axis-label-spa
ing))
Y-axis-label-spa
ing))
This expression returns the value of height itself if the height is an even
multiple of the value of the Y-axis-label-spa
ing or else it
omputes and
returns a value of height that is equal to the next higher multiple of the
value of the Y-axis-label-spa
ing.
We
an now in
lude this expression in the let expression of the print-
graph fun
tion (after rst setting the value of Y-axis-label-spa
ing):
(defvar Y-axis-label-spa
ing 5
"Number of lines from one Y axis label to next.")
...
(let* ((height (apply 'max numbers-list))
(height-of-top-line
(if (zerop (% height Y-axis-label-spa
ing))
height
;; else
(* (1+ (/ height Y-axis-label-spa
ing))
Y-axis-label-spa
ing)))
(symbol-width (length graph-blank))))
...
(Note use of the let* fun
tion: the initial value of height is
omputed on
e
by the (apply 'max numbers-list) expression and then the resulting value
of height is used to
ompute its nal value. See \The let* expression",
page 156, for more about let*.)
To gure out how many leading spa
es the label will need, the fun
tion
subtra
ts the a
tual length of the label|the length of the number plus the
length of the ti
mark|from the desired label width.
Blank spa
es are inserted using the make-string fun
tion. This fun
tion
takes two arguments: the rst tells it how long the string will be and the
se
ond is a symbol for the
hara
ter to insert, in a spe
ial format. The
format is a question mark followed by a blank spa
e, like this, `? '. See
se
tion \Chara
ter Type" in The GNU Ema
s Lisp Referen
e Manual, for a
des
ription of the syntax for
hara
ters.
The number-to-string fun
tion is used in the
on
atenation expression,
to
onvert the number to a string that is
on
atenated with the leading
spa
es and the ti
mark.
we
onstru
t a blank label using the make-string fun
tion. The base line
onsists of the number one followed by a ti
mark.
;; number-of-X-ti
s
(if (zerop (% (X-length ti
-width)))
(/ (X-length ti
-width))
(1+ (/ (X-length ti
-width))))
All this leads us dire
tly to the fun
tion for printing the X axis ti
line:
(defun print-X-axis-ti
-line
(number-of-X-ti
s X-axis-leading-spa
es X-axis-ti
-element)
"Print ti
s for X axis."
(insert X-axis-leading-spa
es)
(insert X-axis-ti
-symbol) ; Under rst
olumn.
;; Insert se
ond ti
in the right spot.
(insert (
on
at
(make-string
(- (* symbol-width X-axis-label-spa
ing)
;; Insert white spa
e up to se
ond ti
symbol.
(* 2 (length X-axis-ti
-symbol)))
? )
X-axis-ti
-symbol))
;; Insert remaining ti
s.
(while (> number-of-X-ti
s 1)
(insert X-axis-ti
-element)
(setq number-of-X-ti
s (1- number-of-X-ti
s))))
Next, we
reate the fun
tion to print the numbered line, starting with
the number \1" under the rst
olumn:
(defun print-X-axis-numbered-line
(number-of-X-ti
s X-axis-leading-spa
es)
"Print line of X-axis numbers"
(let ((number X-axis-label-spa
ing))
(insert X-axis-leading-spa
es)
(insert "1")
266 Appendix C: A Graph with Labelled Axes
(insert (
on
at
(make-string
;; Insert white spa
e up to next number.
(- (* symbol-width X-axis-label-spa
ing) 2)
? )
(number-to-string number)))
;; Insert remaining numbers.
(setq number (+ number X-axis-label-spa
ing))
(while (> number-of-X-ti
s 1)
(insert (X-axis-element number))
(setq number (+ number X-axis-label-spa
ing))
(setq number-of-X-ti
s (1- number-of-X-ti
s)))))
Finally, we need to write the print-X-axis that uses print-X-axis-
ti
-line and print-X-axis-numbered-line.
The fun
tion must determine the lo
al values of the variables used by both
print-X-axis-ti
-line and print-X-axis-numbered-line, and then it
must
all them. Also, it must print the
arriage return that separates the
two lines.
The fun
tion
onsists of a varlist that spe
ies ve lo
al variables, and
alls to ea
h of the two line printing fun
tions:
(defun print-X-axis (numbers-list)
"Print X axis labels to length of NUMBERS-LIST."
(let* ((leading-spa
es
(make-string full-Y-label-width ? ))
;; symbol-width is provided by graph-body-print
(ti
-width (* symbol-width X-axis-label-spa
ing))
(X-length (length numbers-list))
(X-ti
(
on
at
(make-string
;; Make a string of blanks.
(- (* symbol-width X-axis-label-spa
ing)
(length X-axis-ti
-symbol))
? )
;; Con
atenate blanks with ti
symbol.
X-axis-ti
-symbol))
(ti
-number
(if (zerop (% X-length ti
-width))
(/ X-length ti
-width)
(1+ (/ X-length ti
-width)))))
(print-X-axis-ti
-line ti
-number leading-spa
es X-ti
)
(insert "\n")
(print-X-axis-numbered-line ti
-number leading-spa
es)))
Printing the Whole Graph 267
This new feature requires a
hange to the Y-axis-
olumn fun
tion, to
add verti
al-step to it. The fun
tion looks like this:
The values for the maximum height of graph and the width of a symbol
are
omputed by print-graph in its let expression; so graph-body-print
must be
hanged to a
ept them.
Printing the Whole Graph 269
(
on
at
(number-to-string
(* height-of-top-line verti
al-step))
Y-axis-ti
))))
(print-Y-axis
height-of-top-line full-Y-label-width verti
al-step)
(graph-body-print
numbers-list height-of-top-line symbol-width)
(print-X-axis numbers-list)))
*
** *
5 - **** *
**** ***
* *********
************
1 - *************
| | | |
1 5 10 15
On the other hand, if you pass print-graph a verti
al-step value of
2, by evaluating this expression:
(print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1) 2)
Graphing Numbers of Words and Symbols 271
*
** *
10 - **** *
**** ***
* *********
************
2 - *************
| | | |
1 5 10 15
(A question: is the `2' on the bottom of the verti
al axis a bug or a feature?
If you think it is a bug, and should be a `1' instead, (or even a `0'), you
an
modify the sour
es.)
On my ma
hine, this takes about an hour. It looks though 303 Lisp les in
my
opy of Ema
s version 19.23. After all that
omputing, the list-for-
graph has this value:
(537 1027 955 785 594 483 349 292 224 199 166 120 116 99
90 80 67 48 52 45 41 33 28 26 25 20 12 28 11 13 220)
This means that my
opy of Ema
s has 537 fun
tion denitions with fewer
than 10 words or symbols in them, 1,027 fun
tion denitions with 10 to 19
words or symbols in them, 955 fun
tion denitions with 20 to 29 words or
symbols in them, and so on.
Clearly, just by looking at this list we
an see that most fun
tion deni-
tions
ontain ten to thirty words and symbols.
Now for printing. We do not want to print a graph that is 1,030 lines
high . . . Instead, we should print a graph that is fewer than twenty-ve
lines high. A graph that height
an be displayed on almost any monitor,
and easily printed on a sheet of paper.
This means that ea
h value in list-for-graph must be redu
ed to one-
ftieth its present value.
Here is a short fun
tion to do just that, using two fun
tions we have not
yet seen, map
ar and lambda.
(defun one-fiftieth (full-range)
"Return list, ea
h number one-fiftieth of previous."
(map
ar '(lambda (arg) (/ arg 50)) full-range))
Thus,
(lambda (arg) (/ arg 50))
is a fun
tion denition that says `return the value resulting from dividing
whatever is passed to me as arg by 50'.
Earlier, for example, we had a fun
tion multiply-by-seven; it multiplied
its argument by 7. This fun
tion is similar, ex
ept it divides its argument by
50; and, it has no name. The anonymous equivalent of multiply-by-seven
is:
(lambda (number) (* 7 number))
(See Se
tion 3.1, \The defun Spe
ial Form", page 29.)
If we want to multiply 3 by 7, we
an write:
(multiply-by-seven 3)
function argument
This expression returns 2. The 100 is passed to the fun
tion, whi
h divides
that number by 50.
See se
tion \Lambda Expressions" in The GNU Ema
s Lisp Referen
e
Manual, for more about lambda. Lisp and lambda expressions derive from
the Lambda Cal
ulus.
274 Appendix C: A Graph with Labelled Axes
step option. The top-of-range s
ale goes from 10 to 300 by tens. But the
print-graph fun
tion will print only by ones.
This is a
lassi
example of what some
onsider the most insidious type
of bug, the bug of omission. This is not the kind of bug you
an nd by
studying the
ode, for it is not in the
ode; it is an omitted feature. Your
best a
tions are to try your program early and often; and try to arrange,
as mu
h as you
an, to write
ode that is easy to understand and easy to
hange. Try to be aware, whenever you
an, that whatever you have written,
will be rewritten, if not soon, eventually. A hard maxim to follow.
It is the print-X-axis-numbered-line fun
tion that needs the work;
and then the print-X-axis and the print-graph fun
tions need to be
adapted. Not mu
h needs to be done; there is one ni
ety: the numbers
ought to line up under the ti
marks. This takes a little thought.
Here is the
orre
ted print-X-axis-numbered-line:
(defun print-X-axis-numbered-line
(number-of-X-ti
s X-axis-leading-spa
es
&optional horizontal-step)
"Print line of X-axis numbers"
(let ((number X-axis-label-spa
ing)
(horizontal-step (or horizontal-step 1)))
(insert X-axis-leading-spa
es)
;; Delete extra leading spa
es.
(delete-
har
(- (1-
(length (number-to-string horizontal-step)))))
(insert (
on
at
(make-string
;; Insert white spa
e.
(- (* symbol-width
X-axis-label-spa
ing)
(1-
(length
(number-to-string horizontal-step)))
2)
? )
(number-to-string
(* number horizontal-step))))
;; Insert remaining numbers.
(setq number (+ number X-axis-label-spa
ing))
(while (> number-of-X-ti
s 1)
(insert (X-axis-element
(* number horizontal-step)))
(setq number (+ number X-axis-label-spa
ing))
(setq number-of-X-ti
s (1- number-of-X-ti
s)))))
276 Appendix C: A Graph with Labelled Axes
If you are reading this in Info, you
an see the new versions of print-X-
axis print-graph and evaluate them. If you are reading this in a printed
book, you
an see the
hanged lines here (the full text is too mu
h to print).
(defun print-X-axis (numbers-list horizontal-step)
...
(print-X-axis-numbered-line
ti
-number leading-spa
es horizontal-step))
(defun print-graph
(numbers-list
&optional verti
al-step horizontal-step)
...
(print-X-axis numbers-list horizontal-step))
The Printed Graph 277
1000 - *
**
**
**
**
750 - ***
***
***
***
****
500 - *****
******
******
******
*******
250 - ********
********* *
*********** *
************* *
50 - ***************** * *
| | | | | | | |
10 50 100 150 200 250 300 350
You may also lend
opies, under the same
onditions stated above, and
you may publi
ly display
opies.
3. COPYING IN QUANTITY
If you publish printed
opies of the Do
ument numbering more than
100, and the Do
ument's li
ense noti
e requires Cover Texts, you must
en
lose the
opies in
overs that
arry,
learly and legibly, all these Cover
Texts: Front-Cover Texts on the front
over, and Ba
k-Cover Texts on
the ba
k
over. Both
overs must also
learly and legibly identify you as
the publisher of these
opies. The front
over must present the full title
with all words of the title equally prominent and visible. You may add
other material on the
overs in addition. Copying with
hanges limited
to the
overs, as long as they preserve the title of the Do
ument and
satisfy these
onditions,
an be treated as verbatim
opying in other
respe
ts.
If the required texts for either
over are too voluminous to t legibly,
you should put the rst ones listed (as many as t reasonably) on the
a
tual
over, and
ontinue the rest onto adja
ent pages.
If you publish or distribute Opaque
opies of the Do
ument numbering
more than 100, you must either in
lude a ma
hine-readable Transpar-
ent
opy along with ea
h Opaque
opy, or state in or with ea
h Opaque
opy a publi
ly-a
essible
omputer-network lo
ation
ontaining a
om-
plete Transparent
opy of the Do
ument, free of added material, whi
h
the general network-using publi
has a
ess to download anonymously
at no
harge using publi
-standard network proto
ols. If you use the
latter option, you must take reasonably prudent steps, when you begin
distribution of Opaque
opies in quantity, to ensure that this Transpar-
ent
opy will remain thus a
essible at the stated lo
ation until at least
one year after the last time you distribute an Opaque
opy (dire
tly or
through your agents or retailers) of that edition to the publi
.
It is requested, but not required, that you
onta
t the authors of the
Do
ument well before redistributing any large number of
opies, to give
them a
han
e to provide you with an updated version of the Do
ument.
4. MODIFICATIONS
You may
opy and distribute a Modied Version of the Do
ument under
the
onditions of se
tions 2 and 3 above, provided that you release
the Modied Version under pre
isely this Li
ense, with the Modied
Version lling the role of the Do
ument, thus li
ensing distribution and
modi
ation of the Modied Version to whoever possesses a
opy of it.
In addition, you must do these things in the Modied Version:
A. Use in the Title Page (and on the
overs, if any) a title distin
t
from that of the Do
ument, and from those of previous versions
(whi
h should, if there were any, be listed in the History se
tion of
the Do
ument). You may use the same title as a previous version
if the original publisher of that version gives permission.
282 Appendix D: GNU Free Do
umentation Li
ense
You may extra
t a single do
ument from su
h a
olle
tion, and distribute
it individually under this Li
ense, provided you insert a
opy of this
Li
ense into the extra
ted do
ument, and follow this Li
ense in all other
respe
ts regarding verbatim
opying of that do
ument.
7. AGGREGATION WITH INDEPENDENT WORKS
A
ompilation of the Do
ument or its derivatives with other separate
and independent do
uments or works, in or on a volume of a storage
or distribution medium, does not as a whole
ount as a Modied Ver-
sion of the Do
ument, provided no
ompilation
opyright is
laimed for
the
ompilation. Su
h a
ompilation is
alled an \aggregate", and this
Li
ense does not apply to the other self-
ontained works thus
ompiled
with the Do
ument, on a
ount of their being thus
ompiled, if they are
not themselves derivative works of the Do
ument.
If the Cover Text requirement of se
tion 3 is appli
able to these
opies
of the Do
ument, then if the Do
ument is less than one quarter of the
entire aggregate, the Do
ument's Cover Texts may be pla
ed on
overs
that surround only the Do
ument within the aggregate. Otherwise they
must appear on
overs around the whole aggregate.
8. TRANSLATION
Translation is
onsidered a kind of modi
ation, so you may distribute
translations of the Do
ument under the terms of se
tion 4. Repla
ing
Invariant Se
tions with translations requires spe
ial permission from
their
opyright holders, but you may in
lude translations of some or all
Invariant Se
tions in addition to the original versions of these Invariant
Se
tions. You may in
lude a translation of this Li
ense provided that
you also in
lude the original English version of this Li
ense. In
ase of
a disagreement between the translation and the original English version
of this Li
ense, the original English version will prevail.
9. TERMINATION
You may not
opy, modify, subli
ense, or distribute the Do
ument ex-
ept as expressly provided for under this Li
ense. Any other attempt
to
opy, modify, subli
ense or distribute the Do
ument is void, and will
automati
ally terminate your rights under this Li
ense. However, par-
ties who have re
eived
opies, or rights, from you under this Li
ense will
not have their li
enses terminated so long as su
h parties remain in full
omplian
e.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Do
umentation Li
ense from time to time. Su
h
new versions will be similar in spirit to the present version, but
may dier in detail to address new problems or
on
erns. See
http://www.gnu.org/
opyleft/.
Ea
h version of the Li
ense is given a distinguishing version number.
If the Do
ument spe
ies that a parti
ular numbered version of this
GNU Free Do
umentation Li
ense 285
Li
ense \or any later version" applies to it, you have the option of
following the terms and
onditions either of that spe
ied version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Do
ument does not spe
ify a version
number of this Li
ense, you may
hoose any version ever published (not
as a draft) by the Free Software Foundation.
286 Appendix D: GNU Free Do
umentation Li
ense
Index 287
Index
% Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . 12
% (remainder fun
tion) . . . . . . . . . . . . . . 258 Arguments' data types . . . . . . . . . . . . . . . 13
Arguments, variable number of . . . . . . . . 14
Asterisk for read-only buer . . . . . . . . . . 65
( Auto Fill mode turned on . . . . . . . . . . . 218
autoload . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
(debug) in
ode . . . . . . . . . . . . . . . . . . . . 235 Automati
mode sele
tion . . . . . . . . . . . 218
Axis, print horizontal . . . . . . . . . . . . . . . 263
* Axis, print verti
al . . . . . . . . . . . . . . . . . . 256
* (multipli
ation) . . . . . . . . . . . . . . . . . . . . 31
* for read-only buer . . . . . . . . . . . . . . . . . 65 B
`*s
rat
h*' buer . . . . . . . . . . . . . . . . . . 123 beginning-of-buffer . . . . . . . . . . . . . . . . 69
`bind' dened . . . . . . . . . . . . . . . . . . . . . . . 17
. `body' dened . . . . . . . . . . . . . . . . . . . . . . . 30
Body of graph . . . . . . . . . . . . . . . . . . . . . . 203
`.ema
s' le . . . . . . . . . . . . . . . . . . . . . . . . 213 Buer size . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
`.ema
s' le, beginning of . . . . . . . . . . . 216 Buer, history of word . . . . . . . . . . . . . . . 24
buffer-file-name . . . . . . . . . . . . . . . . . . . 23
/ buffer-menu, bound to key . . . . . . . . . 221
buffer-name . . . . . . . . . . . . . . . . . . . . . . . . 23
/ (division) . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Bug, most insidious type . . . . . . . . . . . . 274
Building robots . . . . . . . . . . . . . . . . . . . . . 134
Building Tags in the Ema
s sour
es . . 164
> Byte
ompiling . . . . . . . . . . . . . . . . . . . . . . . 8
> (greater than) . . . . . . . . . . . . . . . . . . . . 40
<
C
C language primitives . . . . . . . . . . . . . . . . 29
<= (less than or equal) . . . . . . . . . . . . . . 127 C, a digression into . . . . . . . . . . . . . . . . . . 98
`
all' dened . . . . . . . . . . . . . . . . . . . . . . . 27
an
el-debug-on-entry . . . . . . . . . . . . . 234
A
ar, introdu
ed . . . . . . . . . . . . . . . . . . . . . 81
A
umulate, type of re
ursive pattern
dr, introdu
ed . . . . . . . . . . . . . . . . . . . . . 81
............................... 142 Changing a fun
tion denition . . . . . . . . 32
add-hook . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Chest of Drawers, metaphor for a symbol
and . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108, 156 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
and, introdu
ed . . . . . . . . . . . . . . . . . . . . 108 Clipping text . . . . . . . . . . . . . . . . . . . . . . . . 89
Anonymous fun
tion . . . . . . . . . . . . . . . . 272 Code installation . . . . . . . . . . . . . . . . . . . . 36
append-to-buffer . . . . . . . . . . . . . . . . . . . 56 `
ommand' dened . . . . . . . . . . . . . . . . . . . . 23
apply . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Comments in Lisp
ode . . . . . . . . . . . . . . 32
apropos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Common Lisp . . . . . . . . . . . . . . . . . . . . . . . xiii
Argument as lo
al variable . . . . . . . . . . 131
ompare-windows . . . . . . . . . . . . . . . . . . . 220
`argument' dened . . . . . . . . . . . . . . . . . . . 12
on
at . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
`argument list' dened . . . . . . . . . . . . . . 30
ond . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Argument, wrong type of . . . . . . . . . . . . . 14
ondition-
ase . . . . . . . . . . . . . . . . . . . . . 95
288 Index
G kill-new . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Generate an error message . . . . . . . . . . . . . 4 kill-region . . . . . . . . . . . . . . . . . . . . . . . . 94
Getting a buer . . . . . . . . . . . . . . . . . . . . . 25 Killing text . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Global set key . . . . . . . . . . . . . . . . . . . . . . 220
global-set-key . . . . . . . . . . . . . . . . . . . . 220
global-unset-key . . . . . . . . . . . . . . . . . . 221
L
Graph prototype . . . . . . . . . . . . . . . . . . . . 203 lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Graph, printing all . . . . . . . . . . . . . . . . . . 267 length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
graph-body-print . . . . . . . . . . . . . . . . . . 208 lengths-list-file . . . . . . . . . . . . . . . . . 188
graph-body-print Final version. . . . . . 268 lengths-list-many-files . . . . . . . . . . 190
let . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
let expression sample . . . . . . . . . . . . . . . . 38
H let expression, parts of . . . . . . . . . . . . . . 37
Handling the kill ring . . . . . . . . . . . . . . . 243 let variables uninitialized . . . . . . . . . . . . 39
Help typing lists . . . . . . . . . . . . . . . . . . . . . . 3 Library, as term for `le' . . . . . . . . . . . . . 52
Horizontal axis printing . . . . . . . . . . . . . 263 line-to-top-of-window . . . . . . . . . . . . . 224
Lisp Atoms . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Lisp history . . . . . . . . . . . . . . . . . . . . . . . . xiii
I Lisp interpreter, explained . . . . . . . . . . . . . 4
if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Lisp interpreter, what it does . . . . . . . . . . 7
`if-part' dened . . . . . . . . . . . . . . . . . . . . 40 Lisp Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
indent-tabs-mode . . . . . . . . . . . . . . . . . . 219 Lisp ma
ro . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Indentation for formatting . . . . . . . . . . . . 58 list-buffers, rebound . . . . . . . . . . . . . 221
Initialization le . . . . . . . . . . . . . . . . . . . . 213 Lists in a
omputer . . . . . . . . . . . . . . . . . 113
Initializing a variable . . . . . . . . . . . . . . . . 100 load-library . . . . . . . . . . . . . . . . . . . . . . 223
Inner list evaluation . . . . . . . . . . . . . . . . . . . 9 load-path . . . . . . . . . . . . . . . . . . . . . . . . . 223
insert-buffer . . . . . . . . . . . . . . . . . . . . . . 64 Loading les . . . . . . . . . . . . . . . . . . . . . . . . 222
insert-buffer-substring . . . . . . . . . . . 56 `lo
al variable' dened . . . . . . . . . . . . . 37
Insidious type of bug . . . . . . . . . . . . . . . . 274 Lo
al variables list, per-buer, . . . . . . . 218
Install a Fun
tion Denition . . . . . . . . . . 31 Lo
ation of point . . . . . . . . . . . . . . . . . . . . 27
Install
ode permanently . . . . . . . . . . . . . 36 looking-at . . . . . . . . . . . . . . . . . . . . . . . . 159
intera
tive . . . . . . . . . . . . . . . . . . . . . . . . 33 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
`intera
tive fun
tion' dened . . . . . . . 23 Loops and re
ursion . . . . . . . . . . . . . . . . . 121
Intera
tive fun
tions . . . . . . . . . . . . . . . . . 33
Intera
tive options . . . . . . . . . . . . . . . . . . . 35
intera
tive, example use of . . . . . . . . . 65 M
Interpreter, Lisp, explained . . . . . . . . . . . . 4 Ma
lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Interpreter, what it does . . . . . . . . . . . . . . . 7 Ma
ro, lisp . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Mail aliases . . . . . . . . . . . . . . . . . . . . . . . . 219
make tags . . . . . . . . . . . . . . . . . . . . . . . . . . 164
K make-string . . . . . . . . . . . . . . . . . . . . . . . 261
Keep, type of re
ursive pattern . . . . . . 143 map
ar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Key setting globally . . . . . . . . . . . . . . . . . 220 mark . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Key unbinding . . . . . . . . . . . . . . . . . . . . . . 221 mark-whole-buffer . . . . . . . . . . . . . . . . . . 54
Keymaps . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 mat
h-beginning . . . . . . . . . . . . . . . . . . . 161
Keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Kill ring handling . . . . . . . . . . . . . . . . . . . 243 message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Kill ring overview . . . . . . . . . . . . . . . . . . . 117 min . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
kill-append . . . . . . . . . . . . . . . . . . . . . . . 104 Mode line format . . . . . . . . . . . . . . . . . . . 228
290 Index
S top-of-ranges . . . . . . . . . . . . . . . . . . . . . 198
Sample let expression . . . . . . . . . . . . . . . 38 triangle-bugged . . . . . . . . . . . . . . . . . . . 231
save-ex
ursion . . . . . . . . . . . . . . . . . . . . . 44 triangle-re
ursively . . . . . . . . . . . . . . 137
save-restri
tion . . . . . . . . . . . . . . . . . . . 77 Truth and falsehood in Ema
s Lisp . . . . 43
sear
h-forward . . . . . . . . . . . . . . . . . . . . . 92 Types of data . . . . . . . . . . . . . . . . . . . . . . . 13
Sear
hes, illustrating . . . . . . . . . . . . . . . . 149
senten
e-end . . . . . . . . . . . . . . . . . . . . . . 149
Senten
es, movement by . . . . . . . . . . . . . 149
U
set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Unbinding key . . . . . . . . . . . . . . . . . . . . . . 221
set-buffer . . . . . . . . . . . . . . . . . . . . . . . . . 26 Uninitialized let variables . . . . . . . . . . . . 39
set
ar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
set
dr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
set
dr, example . . . . . . . . . . . . . . . . . . . 107
V
setq . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Variable initialization . . . . . . . . . . . . . . . 100
Setting a key globally . . . . . . . . . . . . . . . 220 Variable number of arguments . . . . . . . . 14
Setting value of variable . . . . . . . . . . . . . . 17 Variable, example of, fill-
olumn . . . . 10
`side effe
t' dened . . . . . . . . . . . . . . . . . 8 Variable, setting value . . . . . . . . . . . . . . . . 17
Simple extension in `.ema
s' le . . . . . 224 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
simplified-beginning-of-buffer . . . . 52 `varlist' dened . . . . . . . . . . . . . . . . . . . . 37
`site-init.el' init le . . . . . . . . . . . . . . 213 Version of Ema
s,
hoosing . . . . . . . . . . 225
`site-load.el' init le . . . . . . . . . . . . . . 213 Verti
al axis printing . . . . . . . . . . . . . . . . 256
Size of buer . . . . . . . . . . . . . . . . . . . . . . . . 27
Solution without deferment . . . . . . . . . . 145
sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 W
Sour
e level debugger . . . . . . . . . . . . . . . 235 what-line . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Spe
ial form . . . . . . . . . . . . . . . . . . . . . . . . . . 7 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Spe
ial form of defun . . . . . . . . . . . . . . . . 29 Whitespa
e in lists . . . . . . . . . . . . . . . . . . . . 3
Storing and
utting text . . . . . . . . . . . . . . 89 Whole graph printing . . . . . . . . . . . . . . . 267
`string' dened . . . . . . . . . . . . . . . . . . . . . . 3 Widening . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
swit
h-to-buffer . . . . . . . . . . . . . . . . . . . 26 Widening, example of . . . . . . . . . . . . . . . . 78
Swit
hing to a buer . . . . . . . . . . . . . . . . . 26 Word
ounting in a defun . . . . . . . . . . . 181
Symbol names . . . . . . . . . . . . . . . . . . . . . . . . 6 Words and symbols in defun . . . . . . . . . 181
Symbol without fun
tion error . . . . . . . . 11 Words,
ounted re
ursively . . . . . . . . . . 173
Symbol without value error . . . . . . . . . . . 11 Words, dupli
ated . . . . . . . . . . . . . . . . . . 241
Symboli
expressions, introdu
ed . . . . . . . 2 Writing a fun
tion denition . . . . . . . . . . 29
Symbols as a Chest of Drawers . . . . . . . 115 Wrong type of argument . . . . . . . . . . . . . . 14
Syntax
ategories and tables . . . . . . . . . 182
X
T X axis printing . . . . . . . . . . . . . . . . . . . . . 263
Tabs, preventing . . . . . . . . . . . . . . . . . . . . 219 X-axis-element . . . . . . . . . . . . . . . . . . . . 265
`TAGS' le,
reate own . . . . . . . . . . . . . . . 163
Tags in the Ema
s sour
es . . . . . . . . . . . 164
TAGS table, spe
ifying . . . . . . . . . . . . . . . 51 Y
Text between double quotation marks . . 3 Y axis printing . . . . . . . . . . . . . . . . . . . . . 256
Text Mode turned on . . . . . . . . . . . . . . . 218 Y-axis-
olumn . . . . . . . . . . . . . . . . . . . . . 261
Text retrieval . . . . . . . . . . . . . . . . . . . . . . . 117 Y-axis-
olumn Final version. . . . . . . . . 268
the-the . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Y-axis-label-spa
ing . . . . . . . . . . . . . . 259
`then-part' dened . . . . . . . . . . . . . . . . . . 40 Y-axis-ti
. . . . . . . . . . . . . . . . . . . . . . . .260
292 Index