Professional Documents
Culture Documents
Emacs Lisp Intro
Emacs Lisp Intro
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 De nitions . . . . . . . . . . . . . . . . . . 29
4 A Few Bu er{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 pre x 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 di erently 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 di erent 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 on dent 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*' bu er 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 bu er is alled the `*Ba ktra e*'
bu er 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*' bu er, 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 de ne 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 de nition 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 de nition 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 de nition at-
ta hed to it at a time. Otherwise, the omputer would be onfused as to
whi h de nition to use. If this were the ase among people, only one person
in the world ould be named `Bob'. However, the fun tion de nition to whi h
the name refers an be hanged readily. (See Se tion 3.2, \Install a Fun tion
De nition", page 31.)
Sin e Ema s Lisp is large, it is ustomary to name symbols in a way that
identi es 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 de nition, 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 di erent fun tion or it may attempt to repeat ontinually
what it is doing for ever and ever in what is alled an `in nite 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 de nition
atta hed to that name. If a symbol by itself is evaluated, something di erent
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 de nition atta hed to it. The two are di erent. The fun tion
de nition 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 de nition 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 de nition 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 a e ting the ontents of the drawer holding the fun tion de nition,
and vi e-versa.
The variable fill- olumn illustrates a symbol with a value atta hed to
it: in every GNU Ema s bu er, 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 di erent for you in your Info bu er. 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 de nition.
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 di erent 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 de nition.
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
de nition. 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 de nition,
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. Di erent fun tions require di erent 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 di er-
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 o ered as
proof', whi h is to say, `the information o ered', 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 di erent de nitions atta hed to
it at the same time. By ontrast, in Ema s Lisp, a symbol annot have two di erent
fun tion de nitions 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*'
bu er 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 bu er
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 bu er
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
bu er.) 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 e e 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 e e t to the Lisp interpreter, setting the value, an be the primary
e e 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
e e 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 de nition bound to that symbol.
Then the instru tions in the fun tion de nition 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
e e t". In many ases, a fun tion's primary purpose is to reate a side
e e t.
2.1 Bu er Names
The two fun tions, buffer-name and buffer-file-name, show the di er-
en e between a le and a bu er. When you evaluate the following expression,
(buffer-name), the name of the bu er appears in the e ho area. When you
evaluate (buffer-file-name), the name of the le to whi h the bu er 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 bu er are two di erent entities. A le is information re orded
permanently in the omputer (unless you delete it). A bu er, 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 bu er). Usually, a bu er ontains information
that you have opied from a le; we say the bu er is visiting that le. This
opy is what you work on and modify. Changes to the bu er do not hange
24 Chapter 2: Pra ti ing Evaluation
the le, until you save the bu er. When you save the bu er, the bu er 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 bu er 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 bu ers, you will often nd
that people refer to a le when they mean a bu er and vi e-versa. Indeed,
most people say, \I am editing a le," rather than saying, \I am editing a
bu er 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 `bu er', 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 bu er
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 di erent from ea h other, working
at their own speeds, in spurts. The bu er made it possible for them to work
together e e tively. Eventually, the bu er 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 bu ers 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*' bu er on the s reen. This bu er
is not visiting any le. Similarly, a `*Help*' bu er is not asso iated with
any le.
If you swit h to the `*s rat h*' bu er, 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 bu er. However, if you type (buffer-file-name) in
Getting Bu ers 25
the `*s rat h*' bu er 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*' bu er 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*' bu er and want the value
returned by an expression to appear in the `*s rat h*' bu er 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 bu er 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 bu er. But you an do this in any bu er 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*' bu er, other-buffer will
return that bu er.
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 bu er you swit hed ba k from most re ently1 .
The value of point depends, of ourse, on its lo ation within the bu er.
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 bu er. This
is the number 1 unless narrowing is in e e t. (Narrowing is a me hanism
whereby you an restri t yourself, or a program, to operations on just a part
of a bu er. 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 bu er.
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 de nition.
It is helpful to think of the ve parts of a fun tion de nition 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 de nition 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 de nition. In that
de nition, the name refers to a di erent entity than any use of the same name
outside the fun tion de nition. 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 De nition 31
the value it returns is the name of the de ned fun tion.) At the same time,
this a tion installs the fun tion de nition.
(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 e e 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 pre x 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 e e 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 de nitions.
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 de nition, 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
de nition 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 di erent 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 de nition to install it and then
evaluate the two subsequent expressions to pass di erent 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 bu er; 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 bu er 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 bu er, 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 bu er, and restores it, too. This means you an
write ode that will hange the bu er and have save-ex ursion swit h you
ba k to the original bu er. This is how save-ex ursion is used in append-
to-buffer. (See Se tion 4.4, \The De nition 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 e e ts; and save-ex ursion itself is used only for its side
e e t (whi h is restoring the positions of point and mark).
46 Chapter 3: How To Write Fun tion De nitions
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 bu er. This ommand is normally bound to C-x
C-e.
defun De ne 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 de nition.
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 bu er
before evaluating the body of this spe ial form. Restore the
values of point and mark and bu er 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 bu ers).
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 bu er, as a string.
buffer-file-name
Without an argument, return the name of the le the bu er is
visiting.
urrent-buffer
Return the bu er in whi h Ema s is a tive; it may not be the
bu er that is visible on the s reen.
other-buffer
Return the most re ently sele ted bu er (other than the bu er
passed to other-buffer as an argument and other than the
urrent bu er).
swit h-to-buffer
Sele t a bu er 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 bu er 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 bu er.
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 bu er.
point-min
Return the minimum permissible value of point in the urrent
bu er. This is 1, unless narrowing is in e e t.
point-max
Return the value of the maximum permissible value of point in
the urrent bu er. This is the end of the bu er, unless narrowing
is in e e t.
50 Chapter 3: How To Write Fun tion De nitions
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 de nitions, this de nition 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 de nition, the argument list is empty; this means that this
fun tion does not require any arguments. (When we look at the de nition
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 bu er, that is, to the beginning of the
bu er (or to the beginning of the a essible portion of the bu er 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 bu er 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 de nition!
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 Bu er{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 o er 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 de nition is written in the same way as
the beginning-of-buffer de nition 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 bu er 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 e e ts.
The rst line in the body of the save-ex ursion uses the set-buffer
fun tion to hange the urrent bu er to the one spe i ed in the rst argument
to append-to-buffer. (Changing the bu er is the side e e t; as we have
said before, in Lisp, a side e e 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 bu er 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 bu er, 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 bu er that did not
previously exist.
get-buffer- reate also keeps set-buffer from getting an unne essary
error: set-buffer needs a bu er to go to; if you were to spe ify a bu er that
does not exist, Ema s would baulk. Sin e get-buffer- reate will reate a
bu er if none exists, set-buffer is always provided with a bu er.
60 Chapter 4: A Few Bu er{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 bu er
spe i ed as its rst argument and inserts the string into the present bu er.
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 bu er 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 bu er 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 bu er.
hange-bu er
insert-substring-from-oldbuf-into-bu er )
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 bu ers 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 bu er 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 bu er that will
keep its relative position even if text is added to or removed
from the bu er.
goto- har
Set point to the lo ation spe i ed 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 bu er that is passed to the fun tion
as an argument and insert the region into the urrent bu er.
mark-whole-buffer
Mark the whole bu er as a region. Normally bound to C-x h.
set-buffer
Swit h the attention of Ema s to another bu er, but do not
hange the window being displayed. Used when the program
rather than a human is to work on a di erent bu er.
get-buffer- reate
get-buffer
Find a named bu er or reate one if a bu er of that name does
not exist. The get-buffer fun tion returns nil if the named
bu er does not exist.
The rst use of save-ex ursion returns Ema s to the bu er 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 bu er when done|but if the user then swit hes to
the opied-to bu er, 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 Bu er
The asterisk is for the situation when the bu er is a read-only bu er|
a bu er that annot be modi ed. If insert-buffer is alled on a bu er
that is read-only, a message to this e e 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 bu er. 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 pre x 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 bu er.
bufferp Return t if its argument is a bu er; 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 bu er 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 bu er 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 bu er. 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 bu er 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 bu er, 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 di erent 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 de ned in C for speed, the de nition 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 de ned in Ema s Lisp in `subr.el', but its de nition
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 e e 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 de nition 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-e e 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 de ne 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 di eren 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 pre x, in this
ase, a numeri al lo ation in a bu er, 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 bu er
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 di erent from its usual meaning. The `Transient
Mark' and interprogram- ut-fun tion omments explain ertain side-
e e ts.
After you on e set a mark, a bu er 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 di er-
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 di erent 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 di ers in that it determines whether
two representations are a tually the same obje t inside the omputer, but
with di erent 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 modi es 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 de nition that `is not
void'. If the symbol's fun tion de nition 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 di erent 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 de nition 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 a e ting the ontents of the drawer holding the fun tion
de nition, and vi e-versa.
A tually, what is put in ea h drawer is the address of the value or fun tion
de nition. 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 de nition, 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 bu er 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 bu er is put in the kill ring and the yank ommands insert the
appropriate ontents of the kill ring ba k into a bu er (not ne essarily the
original bu er).
A simple C-y (yank) ommand inserts the rst item from the kill ring into
the urrent bu er. 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 di erent.
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 e e 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 de nition 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 di erent 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 di erent 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 di erent. In the jargon, it is a di erent `instan e'.
Eventually, if the program is written orre tly, the `slightly di erent ar-
guments' will be ome suÆ iently di erent 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*' bu er, 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 de nition, 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 i ed as a position in the bu er.
3. The optional third argument spe i es 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 de ned 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 e e 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 e e 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 pre x 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 pre x, if
any, is returned. If there is no ll pre x, this variable returns
nil.
(not (equal fill-prefix "")
This expression he ks whether an existing ll pre x is an empty
string, that is, a string with no hara ters in it. An empty string
is not a useful ll pre x.
(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 modi ed 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 pre x if the ll pre x 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 de ned by "[ \t℄*$".) The `\\|'
de nes 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 pre x
(if fill-prefix-regexp
;; There is a ll pre x; 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 pre x
(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 e e 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 bu er.
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 bu er 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 bu er 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 bu er 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 pre x.
No ll pre x
It is simplest to look at the ode for the ase when there is no ll pre x
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 bu er.
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 di erent, 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 pre x
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 pre x. If there is a ll pre x,
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 bu er.
2. The text following point does not separate paragraphs.
3. The pattern following point is the ll pre x 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 pre x, 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 pre x, 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, make les, 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 e e 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 i es 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 bu er. The end of the a essible part is the end of the bu er
if the bu er is not narrowed; it is the end of the narrowed part
if the bu er 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 identi es 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 bu er 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 de ning 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 bu er'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 di erently 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 di erent 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 de nition:
;;; 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 bu er. 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 bu er, 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 de nition, 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 de ni-
tion and then test the new version of the de nition 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 de nition 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
de nition, and if it is, to return the ount for that de nition. This adds
omplexity to the de nition, 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 bu er on-
taining fun tion de nitions. Point will either be within a fun tion de nition
or not. For ount-words-in-defun to work, point must move to the begin-
ning of the de nition, a ounter must start at zero, and the ounting loop
must stop when point rea hes the end of the de nition.
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 de nition, or else to the beginning of the bu er. 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 de nition. end-of-defun an be used as part
of an expression that determines the position of the end of the de nition.
The set up for ount-words-in-defun takes shape rapidly: rst we move
point to the beginning of the de nition, then we reate a lo al variable to
hold the ount, and nally, we re ord the position of the end of the de nition
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 de nition by a save-ex ursion
expression that returns the value of point after end-of-defun temporarily
moves it to the end of the de nition.
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 de nition.
We have already rede ned 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 de nition 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 de nition 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 de nition:
(defun multiply-by-seven (number)
"Multiply NUMBER by seven."
(* 7 number))
) 10
Su ess! The de nition has 10 words and symbols.
The next problem is to ount the numbers of words and symbols in several
de nitions within a single le.
in onvenient if they are inadvertently modi ed. 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 bu er if it is narrowed. This fun tion
is usually not needed|Ema s reates a fresh bu er if none already exists;
but if a bu er visiting the le already exists Ema s returns that one. In
this ase, the bu er 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 bu er.
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 de nition and onstru ts
a lengths' list ontaining the information.
Ema s kills the bu er 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*' bu er 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 de nition 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 de nition 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 de nitions 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 de ni-
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 de nition 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 on dent 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*' bu er 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 minibu er 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-bu er,
\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 di eren 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 bu ers 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 e e 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
bu ers.
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 de nition:
(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 de nition, 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 de nition, 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 Modi ed 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 rede ne 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 bu er has been modi ed, 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 i ed 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 bu er name.
It is a list beginning (#("%12b" 0 4 .... The #( begins the list.
The `"%12b"' displays the urrent bu er name, using the buffer-name
fun tion with whi h we are familiar; the `12' spe i es 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. (Bu er 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 e e t. `%P' tells you
the per entage of the bu er 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 di erent olors, di erent ommands, and di erent 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 de nition 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 de nition has a bug. You have mistyped `1=' for
`1-'. Here is the broken de nition:
(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 de nition 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*' bu er
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*'
bu er.)
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 de nition. 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*' bu er 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*' bu er; or else, you need to
start the debugger manually as des ribed below.
Read the `*Ba ktra e*' bu er 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 bu er 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 de nition, 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*' bu er 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*' bu er, type d. Ema s will evaluate the rst expres-
sion in triangle-bugged; the bu er 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 de nition.
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*' bu er 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 de nition 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 de nition 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 de nition for Edebug, you must rst
instrument the ode using a di erent ommand. You an do this by posi-
tioning your ursor within the de nition 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 de nition, simply re-evaluate
it with a ommand that does not instrument it. For example, you ould
pla e your ursor after the de nition'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 i ed 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
de nition 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*' bu er 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 de nition 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 bu er.
(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 prede ned
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 di erent kind of
book, a di erent 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 simpli es
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 di erent 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 pre x 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 de nition 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 di erent 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 i es 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 de nitions with fewer
than 10 words or symbols in them, 1,027 fun tion de nitions with 10 to 19
words or symbols in them, 955 fun tion de nitions 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 de ni-
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 de nition 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 Modi ed Version of the Do ument under
the onditions of se tions 2 and 3 above, provided that you release
the Modi ed Version under pre isely this Li ense, with the Modi ed
Version lling the role of the Do ument, thus li ensing distribution and
modi ation of the Modi ed Version to whoever possesses a opy of it.
In addition, you must do these things in the Modi ed 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 Modi ed 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 di er 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 i es 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 i ed 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 bu er . . . . . . . . . . 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 bu er . . . . . . . . . . . . . . . . . 65 B
`*s rat h*' bu er . . . . . . . . . . . . . . . . . . 123 beginning-of-buffer . . . . . . . . . . . . . . . . 69
`bind' de ned . . . . . . . . . . . . . . . . . . . . . . . 17
. `body' de ned . . . . . . . . . . . . . . . . . . . . . . . 30
Body of graph . . . . . . . . . . . . . . . . . . . . . . 203
`.ema s' le . . . . . . . . . . . . . . . . . . . . . . . . 213 Bu er size . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
`.ema s' le, beginning of . . . . . . . . . . . 216 Bu er, 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' de ned . . . . . . . . . . . . . . . . . . . . . . . 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 de nition . . . . . . . . 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' de ned . . . . . . . . . . . . . . . . . . . . 23
apply . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Comments in Lisp ode . . . . . . . . . . . . . . 32
apropos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Common Lisp . . . . . . . . . . . . . . . . . . . . . . . xiii
Argument as lo al variable . . . . . . . . . . 131 ompare-windows . . . . . . . . . . . . . . . . . . . 220
`argument' de ned . . . . . . . . . . . . . . . . . . . 12 on at . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
`argument list' de ned . . . . . . . . . . . . . . 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 bu er . . . . . . . . . . . . . . . . . . . . . 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' de ned . . . . . . . . . . . . . . . . . . . . 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' de ned . . . . . . . . . . . . . 37
Insidious type of bug . . . . . . . . . . . . . . . . 274 Lo al variables list, per-bu er, . . . . . . . 218
Install a Fun tion De nition . . . . . . . . . . 31 Lo ation of point . . . . . . . . . . . . . . . . . . . . 27
Install ode permanently . . . . . . . . . . . . . 36 looking-at . . . . . . . . . . . . . . . . . . . . . . . . 159
intera tive . . . . . . . . . . . . . . . . . . . . . . . . 33 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
`intera tive fun tion' de ned . . . . . . . 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' de ned . . . . . . . . . . . . . . . . . 8 Variable, setting value . . . . . . . . . . . . . . . . 17
Simple extension in `.ema s' le . . . . . 224 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
simplified-beginning-of-buffer . . . . 52 `varlist' de ned . . . . . . . . . . . . . . . . . . . . 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 bu er . . . . . . . . . . . . . . . . . . . . . . . . 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' de ned . . . . . . . . . . . . . . . . . . . . . . 3 Widening . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
swit h-to-buffer . . . . . . . . . . . . . . . . . . . 26 Widening, example of . . . . . . . . . . . . . . . . 78
Swit hing to a bu er . . . . . . . . . . . . . . . . . 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 de nition . . . . . . . . . . 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' de ned . . . . . . . . . . . . . . . . . . 40 Y-axis-ti . . . . . . . . . . . . . . . . . . . . . . . . 260
292 Index