home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Freeware 2001 May
/
SGI Freeware 2001 May - Disc 3.iso
/
dist
/
fw_elisp-intro.idb
/
usr
/
freeware
/
info
/
emacs-lisp-intro.info-7.z
/
emacs-lisp-intro.info-7
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
GNU Info File
|
1998-10-28
|
49.5 KB
|
1,212 lines
This is Info file emacs-lisp-intro.info, produced by Makeinfo version
1.67 from the input file emacs-lisp-intro.texi.
This is an introduction to `Programming in Emacs Lisp', for people
who are not programmers.
Edition 1.05, 21 October 1997
Copyright (C) 1990, '91, '92, '93, '94, '95, '97 Free Software
Foundation, Inc.
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.
Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided also
that the sections entitled "Copying" and "GNU General Public License"
are included exactly as in the original, and provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be stated in a
translation approved by the Free Software Foundation.
File: emacs-lisp-intro.info, Node: kill-ring-yank-pointer, Next: yank nthcdr Exercises, Prev: Kill Ring Overview, Up: Yanking
The `kill-ring-yank-pointer' Variable
=====================================
`kill-ring-yank-pointer' is a variable, just as `kill-ring' is a
variable. It points to something by being bound to the value of what
it points to, like any other Lisp variable.
Thus, if the value of the kill ring is:
("some text" "a different piece of text" "yet more text")
and the `kill-ring-yank-pointer' points to the second clause, the value
of `kill-ring-yank-pointer' is:
("a different piece of text" "yet more text")
As explained in the previous chapter (*note List Implementation::.),
the computer does not keep two different copies of the text being
pointed to by both the `kill-ring' and the `kill-ring-yank-pointer'.
The words "a different piece of text" and "yet more text" are not
duplicated. Instead, the two Lisp variables point to the same pieces of
text. Here is a diagram:
kill-ring kill-ring-yank-pointer
| |
| ___ ___ | ___ ___ ___ ___
---> | | | --> | | | | | |
|___|___|----> |___|___|--> |___|___|--> nil
| | |
| | |
| | --> "yet more text"
| |
| --> "a different piece of text
|
--> "some text"
Both the variable `kill-ring' and the variable
`kill-ring-yank-pointer' are pointers. But the kill ring itself is
usually described as if it were actually what it is composed of. The
`kill-ring' is spoken of as if it were the list rather than that it
points to the list. Conversely, the `kill-ring-yank-pointer' is spoken
of as pointing to a list.
These two ways of talking about the same thing sound confusing at
first but make sense on reflection. The kill ring is generally thought
of as the complete structure of data that holds the information of what
has recently been cut out of the Emacs buffers. The
`kill-ring-yank-pointer' on the other hand, serves to indicate--that
is, to `point to'--that part of the kill ring of which the first
element (the CAR) will be inserted.
The `rotate-yank-pointer' function changes the element in the kill
ring to which the `kill-ring-yank-pointer' points; when the pointer is
set to point to the next element beyond the end of the kill ring, it
automatically sets it to point to the first element of the kill ring.
This is how the list is transformed into a ring. The
`rotate-yank-pointer' function itself is not difficult, but contains
many details. It and the much simpler `yank' and `yank-pop' functions
are described in an appendix. *Note Handling the Kill Ring: Kill Ring.
File: emacs-lisp-intro.info, Node: yank nthcdr Exercises, Prev: kill-ring-yank-pointer, Up: Yanking
Exercises with `yank' and `nthcdr'
==================================
* Using `C-h v' (`describe-variable'), look at the value of your
kill ring. Add several items to your kill ring; look at its value
again. Using `M-y' (`yank-pop)', move all the way around the kill
ring. How many items were in your kill ring? Find the value of
`kill-ring-max'. Was your kill ring full, or could you have kept
more blocks of text within it?
* Using `nthcdr' and `car', construct a series of expressions to
return the first, second, third, and fourth elements of a list.
File: emacs-lisp-intro.info, Node: Loops & Recursion, Next: Regexp Search, Prev: Yanking, Up: Top
Loops and Recursion
*******************
Emacs Lisp has two primary ways to cause an expression, or a series
of expressions, to be evaluated repeatedly: one uses a `while' loop,
and the other uses "recursion".
Repetition can be very valuable. For example, to move forward four
sentences, you need only write a program that will move forward one
sentence and then repeat the process four times. Since a computer does
not get bored or tired, such repetitive action does not have the
deleterious effects that excessive or the wrong kinds of repetition can
have on humans.
* Menu:
* while:: Causing a stretch of code to repeat.
* Recursion:: Causing a function to call itself.
* Looping exercise::
File: emacs-lisp-intro.info, Node: while, Next: Recursion, Prev: Loops & Recursion, Up: Loops & Recursion
`while'
=======
The `while' special form tests whether the value returned by
evaluating its first argument is true or false. This is similar to what
the Lisp interpreter does with an `if'; what the interpreter does next,
however, is different.
In a `while' expression, if the value returned by evaluating the
first argument 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 first argument to
`while' is true or false. If the value returned by evaluating the
first 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 process is called a loop since 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 first 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 expressions in the body will never be evaluated. The
craft of writing a `while' loop consists of choosing a mechanism such
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 consequence 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 successfully never returns a true
value! What this means is that `while' is always evaluated for its
side effects, which is to say, the consequences of evaluating the
expressions within the body of the `while' loop. This makes sense. It
is not the mere act of looping that is desired, but the consequences of
what happens when the expressions in the loop are repeatedly evaluated.
* Menu:
* Loop Example:: A `while' loop that uses a list.
* print-elements-of-list:: Uses `while', `car', `cdr'.
* Incrementing Loop:: A loop with an incrementing counter.
* Decrementing Loop:: A loop with a decrementing counter.
File: emacs-lisp-intro.info, Node: Loop Example, Next: print-elements-of-list, Prev: while, Up: while
A `while' Loop and a List
-------------------------
A common way to control a `while' loop is to test whether a list has
any elements. If it does, the loop is repeated; but if it does not,
the repetition is ended. Since this is an important technique, we will
create a short example to illustrate it.
A simple way to test whether a list has elements is to evaluate the
list: if it has no elements, it is an empty list and will return the
empty list, `()', which is a synonym for `nil' or false. On the other
hand, a list with elements will return those elements when it is
evaluated. Since Lisp considers as true any value that is not `nil', a
list that returns elements will test true in a `while' loop.
For example, you can set the variable `empty-list' to `nil' by
evaluating the following `setq' expression:
(setq empty-list ())
After evaluating the `setq' expression, you can evaluate the variable
`empty-list' in the usual way, by placing the cursor after the symbol
and typing `C-x C-e'; `nil' will appear in your echo area:
empty-list
On the other hand, if you set a variable to be a list with elements,
the list will appear when you evaluate the variable, as you can see by
evaluating the following two expressions:
(setq animals '(giraffe gazelle lion tiger))
animals
Thus, to create a `while' loop that tests whether there are any
items in the list `animals', the first part of the loop will be written
like this:
(while animals
...
When the `while' tests its first argument, the variable `animals' is
evaluated. It returns a list. So long as the list has elements, the
`while' considers the results of the test to be true; but when the list
is empty, it considers the results of the test to be false.
To prevent the `while' loop from running forever, some mechanism
needs to be provided to empty the list eventually. An oft-used
technique is to have one of the subsequent forms in the `while'
expression set the value of the list to be the CDR of the list. Each
time the `cdr' function 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' can
be set to be the CDR of the original list with the following expression:
(setq animals (cdr animals))
If you have evaluated the previous expressions and then evaluate this
expression, you will see `(gazelle lion tiger)' appear in the echo
area. If you evaluate the expression again, `(lion tiger)' will appear
in the echo 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 `cdr' function
repeatedly to cause the true-or-false-test eventually to test false
looks like this:
(while TEST-WHETHER-LIST-IS-EMPTY
BODY...
SET-LIST-TO-CDR-OF-LIST)
This test and use of `cdr' can be put together in a function that
goes through a list and prints each element of the list on a line of its
own.
File: emacs-lisp-intro.info, Node: print-elements-of-list, Next: Incrementing Loop, Prev: Loop Example, Up: while
An Example: `print-elements-of-list'
------------------------------------
The `print-elements-of-list' function illustrates a `while' loop
with a list.
The function requires several lines for its output. Since the echo
area is only one line, we cannot illustrate how it works in the same
way we have been illustrating functions in the past, by evaluating them
inside Info. Instead, you need to copy the necessary expressions to
your `*scratch*' buffer and evaluate them there. You can copy the
expressions by marking the beginning of the region with `C-<SPC>'
(`set-mark-command'), moving the cursor to the end of the region and
then copying the region using `M-w' (`copy-region-as-kill'). In the
`*scratch*' buffer, you can yank the expressions back by typing `C-y'
(`yank').
After you have copied the expressions to the `*scratch*' buffer,
evaluate each expression in turn. Be sure to evaluate the last
expression, `(print-elements-of-list animals)', by typing `C-u C-x
C-e', that is, by giving an argument to `eval-last-sexp'. This will
cause the result of the evaluation to be printed in the `*scratch*'
buffer instead of being printed in the echo area. (Otherwise you will
see something like this in your echo area:
`^Jgiraffe^J^Jgazelle^J^Jlion^J^Jtiger^Jnil', in which each `^J' stands
for the newline that in the `*scratch*' buffer puts each word on its
own line. You can evaluate these expressions right now in the Info
buffer, if you like, to see this effect.)
(setq animals '(giraffe gazelle lion tiger))
(defun print-elements-of-list (list)
"Print each element of LIST on a line of its own."
(while list
(print (car list))
(setq list (cdr list))))
(print-elements-of-list animals)
When you evaluate the three expressions in sequence in the `*scratch*'
buffer, this will be printed in the buffer:
giraffe
gazelle
lion
tiger
nil
Each element of the list is printed on a line of its own (that is
what the function `print' does) and then the value returned by the
function is printed. Since the last expression in the function is the
`while' loop, and since `while' loops always return `nil', a `nil' is
printed after the last element of the list.
File: emacs-lisp-intro.info, Node: Incrementing Loop, Next: Decrementing Loop, Prev: print-elements-of-list, Up: while
A Loop with an Incrementing Counter
-----------------------------------
A loop is not useful unless it stops when it ought. Besides
controlling a loop with a list, a common way of stopping a loop is to
write the first argument as a test that returns false when the correct
number of repetitions are complete. This means that the loop must have
a counter--an expression that counts how many times the loop repeats
itself.
The test can be an expression such as `(< count desired-number)'
which returns `t' for true if the value of `count' is less than the
`desired-number' of repetitions and `nil' for false if the value of
`count' is equal to or is greater than the `desired-number'. The
expression that increments the count can be a simple `setq' such as
`(setq count (1+ count))', where `1+' is a built-in function in Emacs
Lisp that adds 1 to its argument. (The expression `(1+ count)' has the
same result as `(+ count 1)', but is easier for a human to read.)
The template for a `while' loop controlled by an incrementing
counter looks like this:
SET-COUNT-TO-INITIAL-VALUE
(while (< count desired-number) ; true-or-false-test
BODY...
(setq count (1+ count))) ; incrementer
Note that you need to set the initial value of `count'; usually it is
set to 1.
* Menu:
* Incrementing Example:: Counting pebbles in a triangle.
* Inc Example parts:: The parts of the function definition.
* Inc Example altogether:: Putting the function definition together.
File: emacs-lisp-intro.info, Node: Incrementing Example, Next: Inc Example parts, Prev: Incrementing Loop, Up: Incrementing Loop
Example with incrementing counter
.................................
Suppose you are playing on the beach and decide to make a triangle of
pebbles, putting one pebble in the first row, two in the second row,
three in the third row and so on, like this:
*
* *
* * *
* * * *
(About 2500 years ago, Pythagoras and others developed the beginnings of
number theory by considering questions such 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 sequence, 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.
Because both mechanisms illustrate common ways of writing `while'
loops, we will create two examples, one counting up and the other
counting down. In this first 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 once. 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 process many times
instead of doing a more complex process once.
For example, instead of adding up all the pebbles all at once, what
you can do is add the number of pebbles in the first row, 1, to the
number in the second row, 2, and then add the total of those two rows
to the third row, 3. Then you can add the number in the fourth row, 4,
to the total of the first three rows; and so on.
The critical characteristic of the process is that each repetitive
action is simple. In this case, at each step we add only two numbers,
the number of pebbles in the row and the total already found. This
process of adding two numbers is repeated again and again until the last
row has been added to the total of all the preceding rows. In a more
complex loop the repetitive action might not be so simple, but it will
be simpler than doing everything all at once.
File: emacs-lisp-intro.info, Node: Inc Example parts, Next: Inc Example altogether, Prev: Incrementing Example, Up: Incrementing Loop
The parts of the function definition
....................................
The preceding analysis gives us the bones of our function definition:
first, we will need a variable that we can call `total' that will be
the total number of pebbles. This will be the value returned by the
function.
Second, we know that the function will require an argument: this
argument will be the total number of rows in the triangle. It can be
called `number-of-rows'.
Finally, we need a variable to use as a counter. We could call this
variable `counter', but a better name is `row-number'. That is because
what the counter does is count rows, and a program should be written to
be as understandable as possible.
When the Lisp interpreter first starts evaluating the expressions in
the function, the value of `total' should be set to zero, since we have
not added anything to it. Then the function should add the number of
pebbles in the first row to the total, and then add the number of
pebbles in the second to the total, and then add the number of pebbles
in the third row to the total, and so on, until there are no more rows
left to add.
Both `total' and `row-number' are used only inside the function, so
they can be declared as local variables with `let' and given initial
values. Clearly, the initial value for `total' should be 0. The
initial value of `row-number' should be 1, since we start with the
first row. This means that the `let' statement will look like this:
(let ((total 0)
(row-number 1))
BODY...)
After the internal variables are declared and bound to their initial
values, we can begin the `while' loop. The expression that serves as
the test should return a value of `t' for true so long as the
`row-number' is less than or equal to the `number-of-rows'. (If the
expression tests true only so long as the row number is less than the
number of rows in the triangle, the last row will never be added to the
total; hence the row number has to be either less than or equal to the
number of rows.)
Lisp provides the `<=' function that returns true if the value of
its first argument is less than or equal to the value of its second
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 can be found by repeatedly adding the
number of pebbles in a row to the total already found. Since the
number of pebbles in the row is equal to the row number, the total can
be found by adding the row number to the total. (Clearly, in a more
complex situation, the number of pebbles in the row might be related to
the row number in a more complicated way; if this were the case, the
row number would be replaced 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 conditions need to be
established for the next repetition of the loop, if there is one. This
is done by incrementing the value of the `row-number' variable, which
serves as a counter. After the `row-number' variable has been
incremented, 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 Emacs Lisp function `1+' adds 1 to a number, so the
`row-number' variable can be incremented with this expression:
(setq row-number (1+ row-number))
File: emacs-lisp-intro.info, Node: Inc Example altogether, Prev: Inc Example parts, Up: Incrementing Loop
Putting the function definition together
........................................
We have created the parts for the function definition; now we need to
put them together.
First, the contents of the `while' expression:
(while (<= row-number number-of-rows) ; true-or-false-test
(setq total (+ total row-number))
(setq row-number (1+ row-number))) ; incrementer
Along with the `let' expression varlist, this very nearly completes
the body of the function definition. However, it requires one final
element, the need for which is somewhat subtle.
The final touch is to place the variable `total' on a line by itself
after the `while' expression. Otherwise, the value returned by the
whole function is the value of the last expression that is evaluated in
the body of the `let', and this is the value returned by the `while',
which is always `nil'.
This may not be evident at first sight. It almost looks as if the
incrementing expression is the last expression of the whole function.
But that 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 function will look like this:
(defun NAME-OF-FUNCTION (ARGUMENT-LIST)
"DOCUMENTATION..."
(let (VARLIST)
(while (TRUE-OR-FALSE-TEST)
BODY-OF-WHILE... )
... ) ; Need final expression here.
The result of evaluating the `let' is what is going to be returned
by the `defun' since the `let' is not embedded within any containing
list, except for the `defun' as a whole. However, if the `while' is
the last element of the `let' expression, the function will always
return `nil'. This is not what we want! Instead, what we want is the
value of the variable `total'. This is returned by simply placing the
symbol as the last element of the list starting with `let'. It gets
evaluated after the preceding elements of the list are evaluated, which
means it gets evaluated after it has been assigned the correct value
for the total.
It may be easier to see this by printing the list starting with
`let' all on one line. This format makes it evident that the VARLIST
and `while' expressions are the second and third elements of the list
starting with `let', and the `total' is the last element:
(let (VARLIST) (while (TRUE-OR-FALSE-TEST) BODY-OF-WHILE... ) total)
Putting everything together, the `triangle' function definition
looks like this:
(defun triangle (number-of-rows) ; Version with
; incrementing counter.
"Add up the number of pebbles in a triangle.
The first row has one pebble, the second 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))
After you have installed `triangle' by evaluating the function, you
can try it out. Here are two examples:
(triangle 4)
(triangle 7)
The sum of the first four numbers is 10 and the sum of the first seven
numbers is 28.
File: emacs-lisp-intro.info, Node: Decrementing Loop, Prev: Incrementing Loop, Up: while
Loop with a Decrementing Counter
--------------------------------
Another common way to write a `while' loop is to write the test so
that it determines whether a counter is greater than zero. So long as
the counter is greater than zero, the loop is repeated. But when the
counter is equal to or less than zero, the loop is stopped. For this
to work, the counter has to start out greater than zero and then be
made smaller and smaller by one of the forms that is evaluated
repeatedly.
The test will be an expression such as `(> counter 0)' which returns
`t' for true if the value of `counter' is greater than zero, and `nil'
for false if the value of `counter' is equal to or less than zero. The
expression that makes the number smaller and smaller can be a simple
`setq' such as `(setq counter (1- counter))', where `1-' is a built-in
function in Emacs Lisp that subtracts 1 from its argument.
The template for a decrementing `while' loop looks like this:
(while (> counter 0) ; true-or-false-test
BODY...
(setq counter (1- counter))) ; decrementer
* Menu:
* Decrementing Example:: More pebbles on the beach.
* Dec Example parts:: The parts of the function definition.
* Dec Example altogether:: Putting the function definition together.
File: emacs-lisp-intro.info, Node: Decrementing Example, Next: Dec Example parts, Prev: Decrementing Loop, Up: Decrementing Loop
Example with decrementing counter
.................................
To illustrate a loop with a decrementing counter, we will rewrite the
`triangle' function so the counter decreases to zero.
This is the reverse of the earlier version of the function. In this
case, to find out how many pebbles are needed to make a triangle with 3
rows, add the number of pebbles in the third row, 3, to the number in
the preceding row, 2, and then add the total of those two rows to the
row that precedes them, which is 1.
Likewise, to find the number of pebbles in a triangle with 7 rows,
add the number of pebbles in the seventh row, 7, to the number in the
preceding row, which is 6, and then add the total of those two rows to
the row that precedes them, which is 5, and so on. As in the previous
example, each addition only involves adding two numbers, the total of
the rows already added up and the number of pebbles in the row that is
being added to the total. This process of adding two numbers is
repeated again and again until there are no more pebbles to add.
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 preceding row: it is one less than the number in
the row.
File: emacs-lisp-intro.info, Node: Dec Example parts, Next: Dec Example altogether, Prev: Decrementing Example, Up: Decrementing Loop
The parts of the function definition
....................................
We start with three variables: the total number of rows in the
triangle; the number of pebbles in a row; and the total number of
pebbles, which is what we want to calculate. These variables can be
named `number-of-rows', `number-of-pebbles-in-row', and `total',
respectively.
Both `total' and `number-of-pebbles-in-row' are used only inside the
function and are declared with `let'. The initial value of `total'
should, of course, be zero. However, the initial value of
`number-of-pebbles-in-row' should be equal to the number of rows in the
triangle, since the addition will start with the longest row.
This means that the beginning of the `let' expression will look like
this:
(let ((total 0)
(number-of-pebbles-in-row number-of-rows))
BODY...)
The total number of pebbles can be found by repeatedly adding the
number of pebbles in a row to the total already found, that is, by
repeatedly evaluating the following expression:
(setq total (+ total number-of-pebbles-in-row))
After the `number-of-pebbles-in-row' is added to the `total', the
`number-of-pebbles-in-row' should be decremented by one, since the next
time the loop repeats, the preceding row will be added to the total.
The number of pebbles in a preceding row is one less than the number
of pebbles in a row, so the built-in Emacs Lisp function `1-' can be
used to compute the number of pebbles in the preceding row. This can be
done with the following expression:
(setq number-of-pebbles-in-row
(1- number-of-pebbles-in-row))
Finally, we know that the `while' loop should stop making repeated
additions when there are no pebbles in a row. So the test for the
`while' loop is simply:
(while (> number-of-pebbles-in-row 0)
File: emacs-lisp-intro.info, Node: Dec Example altogether, Prev: Dec Example parts, Up: Decrementing Loop
Putting the function definition together
........................................
Putting these expressions together, we have a function definition
that looks like this:
;;; First subtractive version.
(defun triangle (number-of-rows)
"Add up the number of pebbles in a triangle."
(let ((total 0)
(number-of-pebbles-in-row number-of-rows))
(while (> number-of-pebbles-in-row 0)
(setq total (+ total number-of-pebbles-in-row))
(setq number-of-pebbles-in-row
(1- number-of-pebbles-in-row)))
total))
As written, this function works.
However, it turns out that one of the local variables,
`number-of-pebbles-in-row', is unneeded!
When the `triangle' function is evaluated, the symbol
`number-of-rows' will be bound to a number, giving it an initial value.
That number can be changed in the body of the function as if it were a
local variable, without any fear that such a change will effect the
value of the variable outside of the function. This is a very useful
characteristic of Lisp; it means that the variable `number-of-rows' can
be used anywhere in the function where `number-of-pebbles-in-row' is
used.
Here is a second version of the function written a bit more cleanly:
(defun triangle (number) ; Second version.
"Return sum of numbers 1 through NUMBER inclusive."
(let ((total 0))
(while (> number 0)
(setq total (+ total number))
(setq number (1- number)))
total))
In brief, a properly written `while' loop will consist of three
parts:
1. A test that will return false after the loop has repeated itself
the correct number of times.
2. An expression the evaluation of which will return the value desired
after being repeatedly evaluated.
3. An expression to change the value passed to the true-or-false-test
so that the test returns false after the loop has repeated itself
the right number of times.
File: emacs-lisp-intro.info, Node: Recursion, Next: Looping exercise, Prev: while, Up: Loops & Recursion
Recursion
=========
A recursive function contains code that tells itself to evaluate
itself. When the function evaluates itself, it again finds the code
that tells itself to evaluate itself, so the function evaluates itself
again ... and again ... A recursive function will keep telling itself
to evaluate itself again forever unless it is also provided with a stop
condition.
A recursive function typically contains a conditional expression
which has three parts:
1. A true-or-false-test that determines whether the function is called
again, here called the "do-again-test".
2. The name of the function.
3. An expression that causes the conditional expression to test false
after the correct number of repetitions, here called the
"next-step-expression".
Recursive functions can be much simpler than any other kind of
function. Indeed, when people first start to use them, they often look
so mysteriously simple as to be incomprehensible. Like riding a
bicycle, reading a recursive function definition takes a certain knack
which is hard at first but then seems simple.
A template for a recursive function looks like this:
(defun NAME-OF-RECURSIVE-FUNCTION (ARGUMENT-LIST)
"DOCUMENTATION..."
BODY...
(if DO-AGAIN-TEST
(NAME-OF-RECURSIVE-FUNCTION
NEXT-STEP-EXPRESSION)))
Each time the recursive function is evaluated, an argument is bound to
the value of the next-step-expression; and that value is used in the
do-again-test. The next-step-expression is designed so that the
do-again-test returns false when the function should no longer be
repeated.
The do-again-test is sometimes called the "stop condition", since it
stops the repetitions when it tests false.
* Menu:
* Recursion with list:: Using a list as the test whether to recurse.
* Recursive triangle function:: Replacing a `while' loop with recursion.
* Recursion with cond:: Recursion example with a different conditional.
File: emacs-lisp-intro.info, Node: Recursion with list, Next: Recursive triangle function, Prev: Recursion, Up: Recursion
Recursion with a List
---------------------
The example of a `while' loop that printed the elements of a list of
numbers can be written recursively. Here is the code, including an
expression to set the value of the variable `animals' to a list.
This example must be copied to the `*scratch*' buffer and each
expression must be evaluated there. Use `C-u C-x C-e' to evaluate the
`(print-elements-recursively animals)' expression so that the results
are printed in the buffer; otherwise the Lisp interpreter will try to
squeeze the results into the one line of the echo area.
Also, place your cursor immediately after the last closing
parenthesis of the `print-elements-recursively' function, before the
comment. Otherwise, the Lisp interpreter will try to evaluate the
comment.
(setq animals '(giraffe gazelle lion tiger))
(defun print-elements-recursively (list)
"Print each element of LIST on a line of its own.
Uses recursion."
(print (car list)) ; body
(if list ; do-again-test
(print-elements-recursively ; recursive call
(cdr list)))) ; next-step-expression
(print-elements-recursively animals)
The `print-elements-recursively' function first prints the first
element of the list, the CAR of the list. Then, if the list is not
empty, the function invokes itself, but gives itself as its argument,
not the whole list, but the second and subsequent elements of the list,
the CDR of the list.
When this evaluation occurs, the function prints the first element of
the list it receives as its argument (which is the second element of
the original list). Then, the `if' expression is evaluated and when
true, the function calls itself with the CDR of the list it is invoked
with, which (the second time around) is the CDR of the CDR of the
original list.
Each time the function invokes itself, it invokes itself on a shorter
version of the original list. Eventually, the function invokes itself
on an empty list. The `print' function prints the empty list as `nil'.
Next, the conditional expression tests the value of `list'. Since the
value of `list' is `nil', the `if' expression tests false so the
then-part is not evaluated. The function as a whole then returns
`nil'. Consequently, you see `nil' twice when you evaluate the
function.
When you evaluate `(print-elements-recursively animals)' in the
`*scratch*' buffer, you see this result:
giraffe
gazelle
lion
tiger
nil
nil
(The first `nil' is the value of the empty list that is printed; the
second `nil' is the value returned by the whole function.)
File: emacs-lisp-intro.info, Node: Recursive triangle function, Next: Recursion with cond, Prev: Recursion with list, Up: Recursion
Recursion in Place of a Counter
-------------------------------
The `triangle' function described in a previous section can also be
written recursively. It looks like this:
(defun triangle-recursively (number)
"Return the sum of the numbers 1 through NUMBER inclusive.
Uses recursion."
(if (= number 1) ; do-again-test
1 ; then-part
(+ number ; else-part
(triangle-recursively ; recursive call
(1- number))))) ; next-step-expression
(triangle-recursively 7)
You can install this function by evaluating it and then try it by
evaluating `(triangle-recursively 7)'. (Remember to put your cursor
immediately after the last parenthesis of the function definition,
before the comment.)
To understand how this function works, let's consider what happens
in the various cases when the function 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 function has an `if' expression after the documentation string.
It tests whether the value of `number' is equal to 1; if so, Emacs
evaluates the then-part of the `if' expression, which returns the
number 1 as the value of the function. (A triangle with one row has
one pebble in it.)
Suppose, however, that the value of the argument is 2. In this case,
Emacs evaluates the else-part of the `if' expression.
The else-part consists of an addition, the recursive call to
`triangle-recursively' and a decrementing action; and it looks like
this:
(+ number (triangle-recursively (1- number)))
When Emacs evaluates this expression, the innermost expression is
evaluated first; then the other parts in sequence. Here are the steps
in detail:
Step 1 Evaluate the innermost expression.
The innermost expression is `(1- number)' so Emacs decrements the
value of `number' from 2 to 1.
Step 2 Evaluate the `triangle-recursively' function.
It does not matter that this function is contained within itself.
Emacs passes the result Step 1 as the argument used by this
instance of the `triangle-recursively' function
In this case, Emacs evaluates `triangle-recursively' with an
argument of 1. This means that this evaluation of
`triangle-recursively' returns 1.
Step 3 Evaluate the value of `number'.
The variable `number' is the second element of the list that
starts with `+'; its value is 2.
Step 4 Evaluate the `+' expression.
The `+' expression receives two arguments, the first from the
evaluation of `number' (Step 3) and the second from the evaluation
of `triangle-recursively' (Step 2).
The result of the addition is the sum of 2 plus 1, and the number
3 is returned, which is correct. A triangle with two rows has
three pebbles in it.
* Menu:
* Recursive Example arg of 3::
File: emacs-lisp-intro.info, Node: Recursive Example arg of 3, Prev: Recursive triangle function, Up: Recursive triangle function
An argument of 3
................
Suppose that `triangle-recursively' is called with an argument of 3.
Step 1 Evaluate the do-again-test.
The `if' expression is evaluated first. 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 causes
the function to call 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, which
decrements 3 to 2. This is the next-step-expression.
Step 3 Evaluate the `triangle-recursively' function.
The number 2 is passed to the `triangle-recursively' function.
We know what happens when Emacs evaluates `triangle-recursively'
with an argument of 2. After going through the sequence of
actions described earlier, it returns a value of 3. So that is
what will happen here.
Step 4 Evaluate the addition.
3 will be passed as an argument to the addition and will be added
to the number with which the function was called, which is 3.
The value returned by the function as a whole will be 6.
Now that we know what will happen when `triangle-recursively' is
called with an argument of 3, it is evident what will happen if it is
called with an argument of 4:
In the recursive call, the evaluation of
(triangle-recursively (1- 4))
will return the value of evaluating
(triangle-recursively 3)
which is 6 and this value will be added to 4 by the addition in the
third line.
The value returned by the function as a whole will be 10.
Each time `triangle-recursively' is evaluated, it evaluates a
version of itself with a smaller argument, until the argument is small
enough so that it does not evaluate itself.
File: emacs-lisp-intro.info, Node: Recursion with cond, Prev: Recursive triangle function, Up: Recursion
Recursion Example Using `cond'
------------------------------
The version of `triangle-recursively' described earlier is written
with the `if' special form. It can also be written using another
special form called `cond'. The name of the special form `cond' is an
abbreviation of the word `conditional'.
Although the `cond' special form is not used as often in the Emacs
Lisp sources as `if', it is used often enough to justify explaining it.
The template for a `cond' expression looks like this:
(cond
BODY...)
where the BODY is a series of lists.
Written out more fully, the template looks like this:
(cond
((FIRST-TRUE-OR-FALSE-TEST FIRST-CONSEQUENT)
(SECOND-TRUE-OR-FALSE-TEST SECOND-CONSEQUENT)
(THIRD-TRUE-OR-FALSE-TEST THIRD-CONSEQUENT)
...)
When the Lisp interpreter evaluates the `cond' expression, it
evaluates the first element (the CAR or true-or-false-test) of the
first expression in a series of expressions within the body of the
`cond'.
If the true-or-false-test returns `nil' the rest of that expression,
the consequent, is skipped and the true-or-false-test of the next
expression is evaluated. When an expression is found whose
true-or-false-test returns a value that is not `nil', the consequent of
that expression is evaluated. The consequent can be one or more
expressions. If the consequent consists of more than one expression,
the expressions are evaluated in sequence and the value of the last one
is returned. If the expression does not have a consequent, the value
of the true-or-false-test is returned.
If none of the true-or-false-tests test true, the `cond' expression
returns `nil'.
Written using `cond', the `triangle' function looks like this:
(defun triangle-using-cond (number)
(cond ((<= number 0) 0)
((= number 1) 1)
((> number 1)
(+ number (triangle-using-cond (1- number))))))
In this example, the `cond' 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-cond (1- number)))' if the number is greater than 1.
File: emacs-lisp-intro.info, Node: Looping exercise, Prev: Recursion, Up: Loops & Recursion
Looping Exercise
================
* Write a function similar to `triangle' in which each row has a
value which is the square of the row number. Use a `while' loop.
* Write a function similar to `triangle' that multiplies instead of
adds the values.
* Rewrite these two functions recursively. Rewrite these functions
using `cond'.
* Write a function for Texinfo mode that creates an index entry at
the beginning of a paragraph for every `@dfn' within the paragraph.
(In a Texinfo file, `@dfn' marks a definition. For more
information, see *Note Indicating Definitions:
(texinfo)Indicating.)
File: emacs-lisp-intro.info, Node: Regexp Search, Next: Counting Words, Prev: Loops & Recursion, Up: Top
Regular Expression Searches
***************************
Regular expression searches are used extensively in GNU Emacs. The
two functions, `forward-sentence' and `forward-paragraph' illustrate
these searches well.
Regular expression searches are described in *Note Regular
Expression Search: (emacs)Regexp Search, as well as in *Note Regular
Expressions: (elisp)Regular Expressions. In writing this chapter, I am
presuming that you have at least a mild acquaintance with them. The
major point to remember is that regular expressions permit you to
search for patterns as well as for literal strings of characters. For
example, the code in `forward-sentence' searches for the pattern of
possible characters that could mark the end of a sentence, and moves
point to that spot.
Before looking at the code for the `forward-sentence' function, it
is worth considering what the pattern that marks the end of a sentence
must be. The pattern is discussed in the next section; following that
is a description of the regular expression search function,
`re-search-forward'. The `forward-sentence' function is described in
the section following. Finally, the `forward-paragraph' function is
described in the last section of this chapter. `forward-paragraph' is
a complex function that introduces several new features.
* Menu:
* sentence-end:: The regular expression for `sentence-end'.
* re-search-forward:: Very similar to `search-forward'.
* forward-sentence:: A straightforward example of regexp search.
* forward-paragraph:: A somewhat complex example.
* etags:: How to create your own `TAGS' table.
* Regexp Review::
* re-search Exercises::
File: emacs-lisp-intro.info, Node: sentence-end, Next: re-search-forward, Prev: Regexp Search, Up: Regexp Search
The Regular Expression for `sentence-end'
=========================================
The symbol `sentence-end' is bound to the pattern that marks the end
of a sentence. What should this regular expression be?
Clearly, a sentence may be ended by a period, a question mark, or an
exclamation mark. Indeed, only clauses that end with one of those three
characters should be considered the end of a sentence. This means that
the pattern should include the character set:
[.?!]
However, we do not want `forward-sentence' merely to jump to a
period, a question mark, or an exclamation mark, because such a
character might be used in the middle of a sentence. A period, for
example, is used after abbreviations. So other information is needed.
According to convention, you type two spaces after every sentence,
but only one space after a period, a question mark, or an exclamation
mark in the body of a sentence. So a period, a question mark, or an
exclamation mark followed by two spaces is a good indicator of an end
of sentence. However, in a file, the two spaces may instead be a tab
or the end of a line. This means that the regular expression should
include these three items as alternatives. This group of alternatives
will look like this:
\\($\\| \\| \\)
^ ^^
TAB SPC
Here, `$' indicates the end of the line, and I have pointed out where
the tab and two spaces are inserted in the expression. Both are
inserted by putting the actual characters into the expression.
Two backslashes, `\\', are required before the parentheses and
vertical bars: the first backslash to quote the following backslash in
Emacs; and the second to indicate that the following character, the
parenthesis or the vertical bar, is special.
Also, a sentence may be followed by one or more carriage returns,
like this:
[
]*
Like tabs and spaces, a carriage return is inserted into a regular
expression by inserting it literally. The asterisk indicates that the
<RET> is repeated zero or more times.
But a sentence end does not consist only of a period, a question
mark or an exclamation mark followed by appropriate space: a closing
quotation mark or a closing brace of some kind may precede the space.
Indeed more than one such mark or brace may precede the space. These
require a expression that looks like this:
[]\"')}]*
In this expression, the first `]' is the first character in the
expression; the second character is `"', which is preceded by a `\' to
tell Emacs the `"' is *not* special. The last three characters are
`'', `)', and `}'.
All this suggests what the regular expression pattern for matching
the end of a sentence should be; and, indeed, if we evaluate
`sentence-end' we find that it returns the following value:
sentence-end
=> "[.?!][]\"')}]*\\($\\| \\| \\)[
]*"