Emacs Lisp Intro

  • May 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Emacs Lisp Intro as PDF for free.

More details

  • Words: 122,879
  • Pages: 314
An Introdu tion to Programming in Ema s Lisp

An Introdu tion to Programming in Ema s Lisp Se ond Edition

by Robert J. Chassell

1990, 1991, 1992, 1993, 1994, 1995, 1997, 2001, 2002 Free Copyright Software Foundation, In . Published by the Free Software Foundation, In . 59 Temple Pla e, Suite 330 Boston, MA 02111-1307 USA Edition 2.05, 2001 Jan 5 ISBN 1-882114-43-4 Permission is granted to opy, distribute and/or modify this do ument under the terms of the GNU Free Do umentation Li ense, Version 1.1 or any later version published by the Free Software Foundation; there being no Invariant Se tion, with the Front-Cover Texts being \A GNU Manual", and with the Ba k-Cover Texts as in (a) below. A opy of the li ense is in luded in the se tion entitled \GNU Free Do umentation Li ense". (a) The FSF's Ba k-Cover Text is: \You have freedom to opy and modify this GNU Manual, like GNU software. Copies published by the Free Software Foundation raise funds for GNU development."

i

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

1 List Pro essing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1 Lisp Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1.1 Lisp Atoms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1.2 Whitespa e in Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1.3 GNU Ema s Helps You Type Lists . . . . . . . . . . . . . . . 3 1.2 Run a Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.3 Generate an Error Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.4 Symbol Names and Fun tion De nitions . . . . . . . . . . . . . . . . . . 6 1.5 The Lisp Interpreter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.5.1 Byte Compiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.6 Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.6.1 Evaluating Inner Lists . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.7 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.7.1 Error Message for a Symbol Without a Fun tion . . 11 1.7.2 Error Message for a Symbol Without a Value . . . . 11 1.8 Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.8.1 Arguments' Data Types . . . . . . . . . . . . . . . . . . . . . . . . 13 1.8.2 An Argument as the Value of a Variable or List . . 13 1.8.3 Variable Number of Arguments . . . . . . . . . . . . . . . . . 14 1.8.4 Using the Wrong Type Obje t as an Argument . . 14 1.8.5 The message Fun tion . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.9 Setting the Value of a Variable . . . . . . . . . . . . . . . . . . . . . . . . . . 17 1.9.1 Using set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 1.9.2 Using setq . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 1.9.3 Counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.10 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1.11 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

2 Pra ti ing Evaluation . . . . . . . . . . . . . . . . . . . . . 23 2.1 2.2 2.3 2.4 2.5

Bu er Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Getting Bu ers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Swit hing Bu ers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bu er Size and the Lo ation of Point . . . . . . . . . . . . . . . . . . . . Exer ise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23 25 26 27 28

iv

3 How To Write Fun tion De nitions . . . . . . . . 29 3.1 The defun Spe ial Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Install a Fun tion De nition . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 Change a Fun tion De nition . . . . . . . . . . . . . . . . . . . 3.3 Make a Fun tion Intera tive . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 An Intera tive multiply-by-seven . . . . . . . . . . . . . 3.4 Di erent Options for intera tive . . . . . . . . . . . . . . . . . . . . . . 3.5 Install Code Permanently . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6 let . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6.1 The Parts of a let Expression . . . . . . . . . . . . . . . . . . 3.6.2 Sample let Expression . . . . . . . . . . . . . . . . . . . . . . . . . 3.6.3 Uninitialized Variables in a let Statement . . . . . . . 3.7 The if Spe ial Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.7.1 The type-of-animal Fun tion in Detail . . . . . . . . . 3.8 If{then{else Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.9 Truth and Falsehood in Ema s Lisp . . . . . . . . . . . . . . . . . . . . . 3.10 save-ex ursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.10.1 Template for a save-ex ursion Expression . . . . 3.11 Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.12 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29 31 32 33 34 35 36 36 37 38 39 39 41 42 43 44 45 46 50

4 A Few Bu er{Related Fun tions . . . . . . . . . . . 51 4.1 Finding More Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 A Simpli ed beginning-of-buffer De nition . . . . . . . . . . . . 4.3 The De nition of mark-whole-buffer . . . . . . . . . . . . . . . . . . . 4.3.1 Body of mark-whole-buffer .. . . . . . . . . . . . . . . . . . 4.4 The De nition of append-to-buffer . . . . . . . . . . . . . . . . . . . . 4.4.1 The append-to-buffer Intera tive Expression . . . 4.4.2 The Body of append-to-buffer . . . . . . . . . . . . . . . . 4.4.3 save-ex ursion in append-to-buffer . . . . . . . . . . 4.5 Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.6 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

51 52 54 55 56 57 57 58 60 61

v

5 A Few More Complex Fun tions . . . . . . . . . . . 63 5.1 The De nition of opy-to-buffer . . . . . . . . . . . . . . . . . . . . . . . 5.2 The De nition of insert-buffer . . . . . . . . . . . . . . . . . . . . . . . . 5.2.1 The Intera tive Expression in insert-buffer . . . . A Read-only Bu er . . . . . . . . . . . . . . . . . . . . . . . . . . . . `b' in an Intera tive Expression . . . . . . . . . . . . . . . . . 5.2.2 The Body of the insert-buffer Fun tion . . . . . . . 5.2.3 insert-buffer With an if Instead of an or . . . . . 5.2.4 The or in the Body . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.5 The let Expression in insert-buffer . . . . . . . . . . 5.3 Complete De nition of beginning-of-buffer .. . . . . . . . . . . 5.3.1 Optional Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.2 beginning-of-buffer with an Argument . . . . . . . What happens in a large bu er . . . . . . . . . . . . . . . . . What happens in a small bu er . . . . . . . . . . . . . . . . 5.3.3 The Complete beginning-of-buffer .. . . . . . . . . . 5.4 Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5 optional Argument Exer ise . . . . . . . . . . . . . . . . . . . . . . . . . . .

63 64 65 65 65 65 66 67 68 69 70 71 71 72 73 74 75

6 Narrowing and Widening . . . . . . . . . . . . . . . . . . 77 6.1 The save-restri tion Spe ial Form . . . . . . . . . . . . . . . . . . . . 77 6.2 what-line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.3 Exer ise with Narrowing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

7

ar, dr, ons:

Fundamental Fun tions . . . . . 81

7.1 ar and dr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 ons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.1 Find the Length of a List: length . . . . . . . . . . . . . . 7.3 nth dr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4 nth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5 set ar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.6 set dr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.7 Exer ise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81 83 84 85 86 87 88 88

vi

8 Cutting and Storing Text . . . . . . . . . . . . . . . . . 89 8.1 zap-to- har . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.1.1 The intera tive Expression . . . . . . . . . . . . . . . . . . . 90 8.1.2 The Body of zap-to- har . . . . . . . . . . . . . . . . . . . . . . 91 8.1.3 The sear h-forward Fun tion . . . . . . . . . . . . . . . . . 92 8.1.4 The progn Spe ial Form . . . . . . . . . . . . . . . . . . . . . . . 93 8.1.5 Summing up zap-to- har . . . . . . . . . . . . . . . . . . . . . 93 8.2 kill-region . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 8.2.1 ondition- ase .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.2.2 delete-and-extra t-region . . . . . . . . . . . . . . . . . . 96 8.3 delete-and-extra t-region: Digressing into C . . . . . . . . . 98 8.4 Initializing a Variable with defvar . . . . . . . . . . . . . . . . . . . . . 100 8.4.1 defvar and an asterisk . . . . . . . . . . . . . . . . . . . . . . . . 101 8.5 opy-region-as-kill .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 8.5.1 The Body of opy-region-as-kill .. . . . . . . . . . . 103 The kill-append fun tion . . . . . . . . . . . . . . . . . . . . 104 The kill-new fun tion . . . . . . . . . . . . . . . . . . . . . . . 105 8.6 Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 8.7 Sear hing Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

9 How Lists are Implemented . . . . . . . . . . . . . . 113

9.1 Symbols as a Chest of Drawers . . . . . . . . . . . . . . . . . . . . . . . . . 115 9.2 Exer ise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

10 Yanking Text Ba k . . . . . . . . . . . . . . . . . . . . . 117

10.1 Kill Ring Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 10.2 The kill-ring-yank-pointer Variable . . . . . . . . . . . . . . . 117 10.3 Exer ises with yank and nth dr . . . . . . . . . . . . . . . . . . . . . . . 119

11 Loops and Re ursion . . . . . . . . . . . . . . . . . . . . 121 11.1 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1.1 A while Loop and a List . . . . . . . . . . . . . . . . . . . . . 11.1.2 An Example: print-elements-of-list . . . . . . 11.1.3 A Loop with an In rementing Counter . . . . . . . . Example with in rementing ounter . . . . . . . . . . . The parts of the fun tion de nition . . . . . . . . . . . . Putting the fun tion de nition together . . . . . . . . 11.1.4 Loop with a De rementing Counter . . . . . . . . . . . Example with de rementing ounter . . . . . . . . . . . The parts of the fun tion de nition . . . . . . . . . . . . Putting the fun tion de nition together . . . . . . . . 11.2 Save your time: dolist and dotimes . . . . . . . . . . . . . . . . . . The dolist Ma ro . . . . . . . . . . . . . . . . . . . . . . . . . . . The dotimes Ma ro . . . . . . . . . . . . . . . . . . . . . . . . . .

121 122 123 124 125 126 127 129 129 130 130 131 132 133

vii 11.3 Re ursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3.1 Building Robots: Extending the Metaphor . . . . . 11.3.2 The Parts of a Re ursive De nition . . . . . . . . . . . 11.3.3 Re ursion with a List . . . . . . . . . . . . . . . . . . . . . . . . 11.3.4 Re ursion in Pla e of a Counter . . . . . . . . . . . . . . An argument of 3 or 4 . . . . . . . . . . . . . . . . . . . . . . . . 11.3.5 Re ursion Example Using ond . . . . . . . . . . . . . . . 11.3.6 Re ursive Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . Re ursive Pattern: every . . . . . . . . . . . . . . . . . . . . . Re ursive Pattern: a

umulate . . . . . . . . . . . . . . . . Re ursive Pattern: keep . . . . . . . . . . . . . . . . . . . . . . 11.3.7 Re ursion without Deferments . . . . . . . . . . . . . . . . 11.3.8 No Deferment Solution . . . . . . . . . . . . . . . . . . . . . . . 11.4 Looping Exer ise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

134 134 135 136 137 138 139 140 141 142 143 143 145 147

12 Regular Expression Sear hes . . . . . . . . . . . . 149 12.1 The Regular Expression for senten e-end . . . . . . . . . . . . . 12.2 The re-sear h-forward Fun tion . . . . . . . . . . . . . . . . . . . . . 12.3 forward-senten e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The while loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The regular expression sear h . . . . . . . . . . . . . . . . . . . . . . . . 12.4 forward-paragraph: a Goldmine of Fun tions . . . . . . . . . The let* expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The forward motion while loop . . . . . . . . . . . . . . . . . . . . . . Between paragraphs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Within paragraphs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . No ll pre x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . With a ll pre x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.5 Create Your Own `TAGS' File . . . . . . . . . . . . . . . . . . . . . . . . . . 12.6 Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.7 Exer ises with re-sear h-forward . . . . . . . . . . . . . . . . . . . .

149 150 151 153 154 155 156 158 159 160 160 161 161 163 164 166

13 Counting: Repetition and Regexps . . . . . . 167 13.1 The ount-words-region Fun tion . . . . . . . . . . . . . . . . . . . 13.1.1 The Whitespa e Bug in ount-words-region . . 13.2 Count Words Re ursively . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.3 Exer ise: Counting Pun tuation . . . . . . . . . . . . . . . . . . . . . . .

167 170 173 179

viii

14 Counting Words in a defun . . . . . . . . . . . . . . 181 14.1 14.2 14.3 14.4 14.5 14.6 14.7

What to Count? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . What Constitutes a Word or Symbol? . . . . . . . . . . . . . . . . . The ount-words-in-defun Fun tion . . . . . . . . . . . . . . . . . Count Several defuns Within a File . . . . . . . . . . . . . . . . . . . Find a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . lengths-list-file in Detail . . . . . . . . . . . . . . . . . . . . . . . . . Count Words in defuns in Di erent Files . . . . . . . . . . . . . . 14.7.1 The append Fun tion . . . . . . . . . . . . . . . . . . . . . . . . 14.8 Re ursively Count Words in Di erent Files . . . . . . . . . . . . . 14.9 Prepare the Data for Display in a Graph . . . . . . . . . . . . . . . 14.9.1 Sorting Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14.9.2 Making a List of Files . . . . . . . . . . . . . . . . . . . . . . . . 14.9.3 Counting fun tion de nitions . . . . . . . . . . . . . . . . .

181 182 183 186 187 188 190 191 192 193 193 194 197

15 Readying a Graph . . . . . . . . . . . . . . . . . . . . . . 203 15.1 15.2 15.3 15.4

The graph-body-print Fun tion . . . . . . . . . . . . . . . . . . . . . . The re ursive-graph-body-print Fun tion . . . . . . . . . . . Need for Printed Axes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exer ise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

208 210 212 212

16 Your `.ema s' File . . . . . . . . . . . . . . . . . . . . . . . 213 16.1 16.2 16.3 16.4 16.5 16.6 16.7 16.8 16.9 16.10 16.11 16.12 16.13 16.14

Site-wide Initialization Files . . . . . . . . . . . . . . . . . . . . . . . . . . . Spe ifying Variables using def ustom . . . . . . . . . . . . . . . . . . Beginning a `.ema s' File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Text and Auto Fill Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mail Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Indent Tabs Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Some Keybindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Keymaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Loading Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Autoloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A Simple Extension: line-to-top-of-window . . . . . . . . X11 Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mis ellaneous Settings for a `.ema s' File . . . . . . . . . . . . . A Modi ed Mode Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

213 214 216 217 219 219 220 221 222 223 224 226 227 228

17 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 17.1 17.2 17.3 17.4 17.5

231 232 234 235 Debugging Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237

debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . debug-on-entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . debug-on-quit and (debug) . . . . . . . . . . . . . . . . . . . . . . . . . . The edebug Sour e Level Debugger . . . . . . . . . . . . . . . . . . . .

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 . . . . . . . . . . . . . . . . . . . B.1.1 The Body of rotate-yank-pointer .. . . . . . . . . . The else-part of the if expression . . . . . . . . . . . . . The % remainder fun tion . . . . . . . . . . . . . . . . . . . . . Using % in rotate-yank-pointer . . . . . . . . . . . . . Pointing to the last element . . . . . . . . . . . . . . . . . . . B.2 yank . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Passing the argument . . . . . . . . . . . . . . . . . . . . . . . . Passing a negative argument . . . . . . . . . . . . . . . . . . B.3 yank-pop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

243 244 245 247 248 248 249 250 251 252

Appendix C A Graph with Labelled Axes . . . 255 C.1 The print-graph Varlist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.2 The print-Y-axis Fun tion . . . . . . . . . . . . . . . . . . . . . . . . . . . C.2.1 Side Trip: Compute a Remainder . . . . . . . . . . . . . . C.2.2 Constru t a Y Axis Element . . . . . . . . . . . . . . . . . . C.2.3 Create a Y Axis Column . . . . . . . . . . . . . . . . . . . . . . C.2.4 The Not Quite Final Version of print-Y-axis . . C.3 The print-X-axis Fun tion . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3.1 X Axis Ti Marks . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.4 Printing the Whole Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.4.1 Testing print-graph . . . . . . . . . . . . . . . . . . . . . . . . . C.4.2 Graphing Numbers of Words and Symbols . . . . . C.4.3 A lambda Expression: Useful Anonymity . . . . . . . C.4.4 The map ar Fun tion . . . . . . . . . . . . . . . . . . . . . . . . . C.4.5 Another Bug . . . Most Insidious . . . . . . . . . . . . . . C.4.6 The Printed Graph . . . . . . . . . . . . . . . . . . . . . . . . . . .

256 256 258 259 261 262 263 263 267 270 271 272 274 274 277

Appendix D GNU Free Do umentation Li ense . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287

x

On Reading this Text

xi

Prefa e Most of the GNU Ema s integrated environment is written in the programming language alled Ema s Lisp. The ode written in this programming language is the software|the sets of instru tions|that tell the omputer 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 extend 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.

On Reading this Text All through this do ument, you will see little sample programs you an run inside of Ema s. If you read this do ument in Info inside of GNU Ema s, you an run the programs as they appear. (This is easy to do and is explained when the examples are presented.) Alternatively, you an read this introdu tion as a printed book while sitting beside a omputer running Ema s. (This is what I like to do; I like printed books.) If you don't have a running Ema s beside you, you an still read this book, but in this ase, it is best to treat it as a novel or as a travel guide to a ountry not yet visited: interesting, but not the same as being there. Mu h of this introdu tion is dedi ated to walk-throughs or guided tours of ode used in GNU Ema s. These tours are designed for two purposes: rst, to give you familiarity with real, working ode ( ode you use every day); and, se ond, to give you familiarity with the way Ema s works. It is interesting to see how a working environment is implemented. Also, I hope that you will pi k up the habit of browsing through sour e ode. You an learn from it and mine it for ideas. Having GNU Ema s is like having a dragon's ave of treasures. In addition to learning about Ema s as an editor and Ema s Lisp as a programming language, the examples and guided tours will give you an

xii

Prefa e

opportunity to get a quainted with Ema s as a Lisp programming environment. GNU Ema s supports programming and provides tools that you will want to be ome omfortable using, su h as M-. (the key whi h invokes the find-tag ommand). You will also learn about bu ers and other obje ts that are part of the environment. Learning about these features of Ema s is like learning new routes around your home town. Finally, I hope to onvey some of the skills for using Ema s to learn aspe ts of programming that you don't know. You an often use Ema s to help you understand what puzzles you or to nd out how to do something new. This self-relian e is not only a pleasure, but an advantage.

For Whom This is Written This text is written as an elementary introdu tion for people who are not programmers. If you are a programmer, you may not be satis ed with this primer. The reason is that you may have be ome expert at reading referen e manuals and be put o by the way this text is organized. An expert programmer who reviewed this text said to me: I prefer to learn from referen e manuals. I \dive into" ea h paragraph, and \ ome up for air" between paragraphs. When I get to the end of a paragraph, I assume that that subje t is done, nished, that I know everything I need (with the possible ex eption of the ase when the next paragraph starts talking about it in more detail). I expe t that a well written referen e manual will not have a lot of redundan y, and that it will have ex ellent pointers to the (one) pla e where the information I want is. This introdu tion is not written for this person! Firstly, I try to say everything at least three times: rst, to introdu e it; se ond, to show it in ontext; and third, to show it in a di erent ontext, or to review it. Se ondly, I hardly ever put all the information about a subje t in one pla e, mu h less in one paragraph. To my way of thinking, that imposes too heavy a burden on the reader. Instead I try to explain only what you need to know at the time. (Sometimes I in lude a little extra information so you won't be surprised later when the additional information is formally introdu ed.) When you read this text, you are not expe ted to learn everything the rst time. Frequently, you need only make, as it were, a `nodding a quaintan e' with some of the items mentioned. My hope is that I have stru tured the text and given you enough hints that you will be alert to what is important, and on entrate on it. You will need to \dive into" some paragraphs; there is no other way to read them. But I have tried to keep down the number of su h paragraphs.

A Note for Novi es

xiii

This book is intended as an approa hable hill, rather than as a daunting mountain. This introdu tion to Programming in Ema s Lisp has a ompanion do ument, The GNU Ema s Lisp Referen e Manual. The referen e manual has more detail than this introdu tion. In the referen e manual, all the information about one topi is on entrated in one pla e. You should turn to it if you are like the programmer quoted above. And, of ourse, after you have read this Introdu tion, you will nd the Referen e Manual useful when you are writing your own programs.

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.)

A Note for Novi es If you don't know GNU Ema s, you an still read this do ument profitably. However, I re ommend you learn Ema s, if only to learn to move around your omputer s reen. You an tea h yourself how to use Ema s with the on-line tutorial. To use it, type C-h t. (This means you press and release the hCTRLi key and the h at the same time, and then press and release t.) Also, I often refer to one of Ema s' standard ommands by listing the keys whi h you press to invoke the ommand and then giving the name of the ommand in parentheses, like this: M-C-\ (indent-region). What this means is that the indent-region ommand is ustomarily invoked by typing M-C-\. (You an, if you wish, hange the keys that are typed to invoke the

ommand; this is alled rebinding. See Se tion 16.8, \Keymaps", page 221.) The abbreviation M-C-\ means that you type your hMETAi key, hCTRLi key and h\i key all at the same time. (On many modern keyboards the hMETAi key is labelled hALTi.) Sometimes a ombination like this is alled a key hord, sin e it is similar to the way you play a hord on a piano. If your keyboard does not have a hMETAi key, the hESCi key pre x is used in pla e of it. In this ase, M-C-\ means that you press and release your hESCi key and then type the hCTRLi key and the h\i key at the same time. But usually M-C-\ means press the hCTRLi key along with the key that is labelled hALTi and, at the same time, press the h\i key.

xiv

Prefa e 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 ouragement. My mistakes are my own. Robert J. Chassell

Lisp Atoms

1

1 List Pro essing To the untutored eye, Lisp is a strange programming language. In Lisp

ode there are parentheses everywhere. Some people even laim that the name stands for `Lots of Isolated Silly Parentheses'. But the laim is unwarranted. Lisp stands for LISt Pro essing, and the programming language handles lists (and lists of lists) by putting them between parentheses. The parentheses mark the boundaries of the list. Sometimes a list is pre eded by a single apostrophe or quotation mark, `''. Lists are the basis of Lisp.

1.1 Lisp Lists In Lisp, a list looks like this: '(rose violet daisy butter up). This list is pre eded by a single apostrophe. It ould just as well be written as follows, whi h looks more like the kind of list you are likely to be familiar with: '(rose violet daisy butter up)

The elements of this list are the names of the four di erent owers, separated from ea h other by whitespa e and surrounded by parentheses, like owers in a eld with a stone wall around them. Lists an also have numbers in them, as in this list: (+ 2 2). This list has a plus-sign, `+', followed by two `2's, ea h separated by whitespa e. In Lisp, both data and programs are represented the same way; that is, they are both lists of words, numbers, or other lists, separated by whitespa e and surrounded by parentheses. (Sin e a program looks like data, one program may easily serve as data for another; this is a very powerful feature of Lisp.) (In identally, these two parentheti al remarks are not Lisp lists, be ause they ontain `;' and `.' as pun tuation marks.) Here is another list, this time with a list inside of it: '(this list has (a list inside of it))

The omponents of this list are the words `this', `list', `has', and the list `(a list inside of it)'. The interior list is made up of the words `a', `list', `inside', `of', `it'.

1.1.1 Lisp Atoms In Lisp, what we have been alling words are alled atoms. This term

omes from the histori al meaning of the word atom, whi h means `indivisible'. As far as Lisp is on erned, the words we have been using in the lists

annot be divided into any smaller parts and still mean the same thing as part of a program; likewise with numbers and single hara ter symbols like

2

Chapter 1: List Pro essing

`+'. 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.) In a list, atoms are separated from ea h other by whitespa e. They an be right next to a parenthesis. Te hni ally speaking, a list in Lisp onsists of parentheses surrounding atoms separated by whitespa e or surrounding other lists or surrounding both atoms and other lists. A list an have just one atom in it or have nothing in it at all. A list with nothing in it looks like this: (), and is alled the empty list. Unlike anything else, an empty list is onsidered both an atom and a list at the same time. 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. As in English, the meanings of the omponent letters of a Lisp atom are di erent from the meaning the letters make as a word. For example, the word for the South Ameri an sloth, the `ai', is ompletely di erent from the two words, `a', and `i'. 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

In addition, text between double quotation marks|even senten es or paragraphs|is an atom. Here is an example: '(this list in ludes "text between quotation marks.")

In Lisp, all of the quoted text in luding the pun tuation mark and the blank spa es is a single atom. This kind of atom is alled a string (for `string of hara ters') and is the sort of thing that is used for messages that a

omputer an print for a human to read. Strings are a di erent kind of atom than numbers or symbols and are used di erently.

1.1.2 Whitespa e in Lists The amount of whitespa e in a list does not matter. From the point of view of the Lisp language, '(this list looks like this)

is exa tly the same as this: '(this list looks like this)

Both examples show what to Lisp is the same list, the list made up of the symbols `this', `list', `looks', `like', and `this' in that order. Extra whitespa e and newlines are designed to make a list more readable by humans. When Lisp reads the expression, it gets rid of all the extra whitespa e (but it needs to have at least one spa e between atoms in order to tell them apart.) Odd as it seems, the examples we have seen over almost all of what Lisp lists look like! Every other list in Lisp looks more or less like one of these examples, ex ept that the list may be longer and more omplex. In brief, a list is between parentheses, a string is between quotation marks, a symbol looks like a word, and a number looks like a number. (For ertain situations, square bra kets, dots and a few other spe ial hara ters may be used; however, we will go quite far without them.)

1.1.3 GNU Ema s Helps You Type Lists When you type a Lisp expression in GNU Ema s using either Lisp Intera tion mode or Ema s Lisp mode, you have available to you several ommands to format the Lisp expression so it is easy to read. For example, pressing the hTABi key automati ally indents the line the ursor is on by the right amount. A ommand to properly indent the ode in a region is ustomarily bound to M-C-\. Indentation is designed so that you an see whi h elements of a list belongs to whi h list|elements of a sub-list are indented more than the elements of the en losing list. In addition, when you type a losing parenthesis, Ema s momentarily jumps the ursor ba k to the mat hing opening parenthesis, so you an see whi h one it is. This is very useful, sin e every list you type in Lisp must have

4

Chapter 1: List Pro essing

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.)

1.2 Run a Program A list in Lisp|any list|is a program ready to run. If you run it (for whi h the Lisp jargon is evaluate), the omputer will do one of three things: do nothing ex ept return to you the list itself; send you an error message; or, treat the rst symbol in the list as a ommand to do something. (Usually, of ourse, it is the last of these three things that you really want!) The single apostrophe, ', that I put in front of some of the example lists in pre eding se tions is alled a quote; when it pre edes a list, it tells Lisp to do nothing with the list, other than take it as it is written. But if there is no quote pre eding a list, the rst item of the list is spe ial: it is a ommand for the omputer to obey. (In Lisp, these ommands are alled fun tions.) The list (+ 2 2) shown above did not have a quote in front of it, so Lisp understands that the + is an instru tion to do something with the rest of the list: add the numbers that follow. If you are reading this inside of GNU Ema s in Info, here is how you

an evaluate su h a list: pla e your ursor immediately after the right hand parenthesis of the following list and then type C-x C-e: (+ 2 2)

You will see the number 4 appear in the e ho area. (In the jargon, what you have just done is \evaluate the list." The e ho area is the line at the bottom of the s reen that displays or \e hoes" text.) Now try the same thing with a quoted list: pla e the ursor right after the following list and type C-x C-e: '(this is a quoted list)

You will see (this is a quoted list) appear in the e ho area. In both ases, what you are doing is giving a ommand to the program inside of GNU Ema s alled the Lisp interpreter|giving the interpreter a

ommand to evaluate the expression. The name of the Lisp interpreter omes from the word for the task done by a human who omes up with the meaning of an expression|who \interprets" it. You an also evaluate an atom that is not part of a list|one that is not surrounded by parentheses; again, the Lisp interpreter translates from the humanly readable expression to the language of the omputer. But before dis ussing this (see Se tion 1.7, \Variables", page 10), we will dis uss what the Lisp interpreter does when you make an error.

1.3 Generate an Error Message Partly so you won't worry if you do it a

identally, we will now give a

ommand to the Lisp interpreter that generates an error message. This is a

Generate an Error Message

5

harmless a tivity; and indeed, we will often try to generate error messages intentionally. On e you understand the jargon, error messages an be informative. 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 instru 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.

1.4 Symbol Names and Fun tion De nitions We an arti ulate another hara teristi of Lisp based on what we have dis ussed so far|an important hara teristi : a symbol, like +, is not itself the set of instru tions for the omputer to arry out. Instead, the symbol is used, perhaps temporarily, as a way of lo ating the de nition or set of instru tions. What we see is the name through whi h the instru tions an be found. Names of people work the same way. I an be referred to as

The Lisp Interpreter

7

`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 atta 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-'.

1.5 The Lisp Interpreter Based on what we have seen, we an now start to gure out what the Lisp interpreter does when we ommand it to evaluate a list. First, it looks to see whether there is a quote before the list; if there is, the interpreter just gives us the list. On the other hand, if there is no quote, the interpreter looks at the rst element in the list and sees whether it has a fun tion de nition. If it does, the interpreter arries out the instru tions in the fun tion de nition. Otherwise, the interpreter prints an error message. This is how Lisp works. Simple. There are added ompli ations whi h we will get to in a minute, but these are the fundamentals. Of ourse, to write Lisp programs, you need to know how to write fun tion de nitions and atta h them to names, and how to do this without onfusing either yourself or the omputer. Now, for the rst ompli ation. In addition to lists, the Lisp interpreter

an evaluate a symbol that is not quoted and does not have parentheses around it. The Lisp interpreter will attempt to determine the symbol's value as a variable. This situation is des ribed in the se tion on variables. (See Se tion 1.7, \Variables", page 10.) The se ond ompli ation o

urs be ause some fun tions are unusual and do not work in the usual manner. Those that don't are alled spe ial forms. They are used for spe ial jobs, like de ning a fun tion, and there are not many of them. In the next few hapters, you will be introdu ed to several of the more important spe ial forms.

8

Chapter 1: List Pro essing

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.5.1 Byte Compiling One other aspe t of interpreting: the Lisp interpreter is able to interpret two kinds of entity: humanly readable ode, on whi h we will fo us ex lusively, and spe ially pro essed ode, alled byte ompiled ode, whi h is not humanly readable. Byte ompiled ode runs faster than humanly readable

ode. You an transform humanly readable ode into byte ompiled ode by running one of the ompile ommands su h as byte- ompile-file. Byte

ompiled ode is usually stored in a le that ends with a `.el ' extension rather than a `.el' extension. You will see both kinds of le in the `ema s/lisp' dire tory; the les to read are those with `.el' extensions. As a pra ti al matter, for most things you might do to ustomize or extend Ema s, you do not need to byte ompile; and I will not dis uss the topi here. See se tion \Byte Compilation" in The GNU Ema s Lisp Referen e Manual, for a full des ription of byte ompilation.

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 expression'. 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

At the same time the interpreter returns a value, it may do something else as well, su h as move a ursor or opy a le; this other kind of a tion is alled a side e e t. A tions that we humans think are important, su h as printing results, are often \side e e ts" to the Lisp interpreter. The jargon

an sound pe uliar, but it turns out that it is fairly easy to learn to use side e e ts. In summary, evaluating a symboli expression most ommonly auses the Lisp interpreter to return a value and perhaps arry out a side e e t; or else produ e an error.

1.6.1 Evaluating Inner Lists If evaluation applies to a list that is inside another list, the outer list may use the value returned by the rst evaluation as information when the outer list is evaluated. This explains why inner expressions are evaluated rst: the values they return are used by the outer expressions. We an investigate this pro ess by evaluating another addition example. Pla e your ursor after the following expression and type C-x C-e: (+ 2 (+ 3 3))

The number 8 will appear in the e ho area. What happens is that the Lisp interpreter rst evaluates the inner expression, (+ 3 3), for whi h the value 6 is returned; then it evaluates the outer expression as if it were written (+ 2 6), whi h returns the value 8. Sin e there are no more en losing expressions to evaluate, the interpreter prints that value in the e ho area. Now it is easy to understand the name of the ommand invoked by the keystrokes C-x C-e: the name is eval-last-sexp. The letters sexp are an abbreviation for `symboli expression', and eval is an abbreviation for `evaluate'. The ommand means `evaluate last symboli expression'. As an experiment, you an try evaluating the expression by putting the

ursor at the beginning of the next line immediately following the expression, or inside the expression. Here is another opy of the expression: (+ 2 (+ 3 3))

If you pla e the ursor at the beginning of the blank line that immediately follows the expression and type C-x C-e, you will still get the value 8 printed in the e ho area. Now try putting the ursor inside the expression. If you put it right after the next to last parenthesis (so it appears to sit on top of the last parenthesis), you will get a 6 printed in the e ho area! This is be ause the ommand evaluates the expression (+ 3 3). Now put the ursor immediately after a number. Type C-x C-e and you will get the number itself. In Lisp, if you evaluate a number, you get the number itself|this is how numbers di er from symbols. If you evaluate a list starting with a symbol like +, you will get a value returned that is the

10

Chapter 1: List Pro essing

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

1.7.1 Error Message for a Symbol Without a Fun tion When we evaluated fill- olumn to nd its value as a variable, we did not pla e parentheses around the word. This is be ause we did not intend to use it as a fun tion name. If fill- olumn were the rst or only element of a list, the Lisp interpreter would attempt to nd the fun tion de nition atta hed to it. But fill olumn has no fun tion de nition. Try evaluating this: (fill- olumn)

In GNU Ema s version 21, you will reate a `*Ba ktra e*' bu er that says: ---------- Buffer: *Ba ktra e* ---------Debugger entered--Lisp error: (void-fun tion fill- olumn) (fill- olumn) eval((fill- olumn)) eval-last-sexp-1(nil) eval-last-sexp(nil)

all-intera tively(eval-last-sexp) ---------- Buffer: *Ba ktra e* ----------

(Remember, to quit the debugger and make the debugger window go away, type q in the `*Ba ktra e*' bu er.) In GNU Ema s 20 and before, you will produ e an error message that says: Symbol's fun tion definition is void: fill- olumn

(The message will go away away as soon as you move the ursor or type another key.)

1.7.2 Error Message for a Symbol Without a Value If you attempt to evaluate a symbol that does not have a value bound to it, you will re eive an error message. You an see this by experimenting with our 2 plus 2 addition. In the following expression, put your ursor right after the +, before the rst number 2, type C-x C-e: (+ 2 2)

In GNU Ema s 21, you will reate a `*Ba ktra e*' bu er that says: ---------- Buffer: *Ba ktra e* ---------Debugger entered--Lisp error: (void-variable +) eval(+) eval-last-sexp-1(nil) eval-last-sexp(nil)

all-intera tively(eval-last-sexp) ---------- Buffer: *Ba ktra e* ----------

(As with the other times we entered the debugger, you an quit by typing q in the `*Ba ktra e*' bu er.)

12

Chapter 1: List Pro essing

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 onsequen 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 erent 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

1.8.1 Arguments' Data Types The type of data that should be passed to a fun tion depends on what kind of information it uses. The arguments to a fun tion su h as + must have values that are numbers, sin e + adds numbers. Other fun tions use di erent kinds of data for their arguments. For example, the on at fun tion links together or unites two or more strings of text to produ e a string. The arguments are strings. Con atenating the two hara ter strings ab , def produ es the single string ab def. This an be seen by evaluating the following: ( on at "ab " "def")

The value produ ed by evaluating this expression is "ab def". A fun tion su h as substring uses both a string and numbers as arguments. The fun tion returns a part of the string, a substring of the rst argument. This fun tion takes three arguments. Its rst argument is the string of hara ters, the se ond and third arguments are numbers that indi ate the beginning and end of the substring. The numbers are a ount of the number of hara ters (in luding spa es and pun tuations) from the beginning of the string. For example, if you evaluate the following: (substring "The qui k brown fox jumped." 16 19)

you will see "fox" appear in the e ho area. The arguments are the string and the two numbers. Note that the string passed to substring is a single atom even though it is made up of several words separated by spa es. Lisp ounts everything between the two quotation marks as part of the string, in luding the spa es. You an think of the substring fun tion as a kind of `atom smasher' sin e it takes an otherwise indivisible atom and extra ts a part. However, substring is only able to extra t a substring from an argument that is a string, not from another type of atom su h as a number or symbol.

1.8.2 An Argument as the Value of a Variable or List An argument an be a symbol that returns a value when it is evaluated. For example, when the symbol fill- olumn by itself is evaluated, it returns a number. This number an be used in an addition. Position the ursor after the following expression and type C-x C-e: (+ 2 fill- olumn)

The value will be a number two more than what you get by evaluating fill- olumn alone. For me, this is 74, be ause the value of fill- olumn is 72. As we have just seen, an argument an be a symbol that returns a value when evaluated. In addition, an argument an be a list that returns a value when it is evaluated. For example, in the following expression, the arguments

14

Chapter 1: List Pro essing

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. numberto-string is also known as int-to-string.)

1.8.3 Variable Number of Arguments Some fun tions, su h as on at, + or *, take any number of arguments. (The * is the symbol for multipli ation.) This an be seen by evaluating ea h of the following expressions in the usual way. What you will see in the e ho area is printed in this text after `)', whi h you may read as `evaluates to'. In the rst set, the fun tions have no arguments: (+)

) 0

(*)

) 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

1.8.4 Using the Wrong Type Obje t as an Argument When a fun tion is passed an argument of the wrong type, the Lisp interpreter produ es an error message. For example, the + fun tion expe ts the values of its arguments to be numbers. As an experiment we an pass it the quoted symbol hello instead of a number. Position the ursor after the following expression and type C-x C-e: (+ 2 'hello)

When you do this you will generate an error message. What has happened is that + has tried to add the 2 to the value returned by 'hello, but the value returned by 'hello is the symbol hello, not a number. Only numbers an be added. So + ould not arry out its addition.

Using the Wrong Type Obje t as an Argument

15

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 trying 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

In GNU Ema s version 20 and before, the e ho area displays an error message that says: Wrong type argument: number-or-marker-p, hello

This says, in di erent words, the same as the top line of the `*Ba ktra e*' bu er.

1.8.5 The message Fun tion Like +, the message fun tion takes a variable number of arguments. It is used to send messages to the user and is so useful that we will des ribe it here. A message is printed in the e ho area. For example, you an print a message in your e ho area by evaluating the following list: (message "This message appears in the e ho area!")

The whole string between double quotation marks is a single argument and is printed in toto. (Note that in this example, the message itself will appear in the e ho area within double quotes; that is be ause you see the value returned by the message fun tion. In most uses of message in programs that you write, the text will be printed in the e ho area as a side-e e t, without the quotes. See Se tion 3.3.1, \multiply-by-seven in detail", page 34, for an example of this.) However, if there is a `%s' in the quoted string of hara ters, the message fun tion does not print the `%s' as su h, but looks to the argument that follows the string. It evaluates the se ond argument and prints the value at the lo ation in the string where the `%s' is. You an see this by positioning the ursor after the following expression and typing C-x C-e: (message "The name of this buffer is: %s." (buffer-name))

In Info, "The name of this buffer is: *info*." will appear in the e ho area. The fun tion buffer-name returns the name of the bu er as a string, whi h the message fun tion inserts in pla e of %s. To print a value as an integer, use `%d' in the same way as `%s'. For example, to print a message in the e ho area that states the value of the fill- olumn, evaluate the following: (message "The value of fill- olumn is %d." fill- olumn)

On my system, when I evaluate this list, "The value of fill- olumn is 72." appears in my e ho area2 . If there is more than one `%s' in the quoted string, the value of the rst argument following the quoted string is printed at the lo ation of the rst `%s' and the value of the se ond argument is printed at the lo ation of the se ond `%s', and so on. 2

A tually, you an use %s to print a number. It is non-spe i . %d prints only the part of a number left of a de imal point, and not anything that is not a number.

Using set

17

For example, if you evaluate the following, (message "There are %d %s in the offi e!" (- fill- olumn 14) "pink elephants")

a rather whimsi al message will appear in your e ho area. On my system it says, "There are 58 pink elephants in the offi e!". The expression (- fill- olumn 14) is evaluated and the resulting number is inserted in pla e of the `%d'; and the string in double quotes, "pink elephants", is treated as a single argument and inserted in pla e of the `%s'. (That is to say, a string between double quotes evaluates to itself, like a number.) Finally, here is a somewhat omplex example that not only illustrates the omputation of a number, but also shows how you an use an expression within an expression to generate the text that is substituted for `%s': (message "He saw %d %s" (- fill- olumn 34) ( on at "red " (substring "The qui k brown foxes jumped." 16 21) " leaping."))

In this example, message has three arguments: the string, "He saw %d %s", the expression, (- fill- olumn 32), and the expression beginning with the fun tion on at. The value resulting from the evaluation of (- fill olumn 32) is inserted in pla e of the `%d'; and the value returned by the expression beginning with on at is inserted in pla e of the `%s'. When I evaluate the expression, the message "He saw 38 red foxes leaping." appears in my e ho area.

1.9 Setting the Value of a Variable There are several ways by whi h a variable an be given a value. One of the ways is to use either the fun tion set or the fun tion setq. Another way is to use let (see Se tion 3.6, \let", page 36). (The jargon for this pro ess is to bind a variable to a value.) The following se tions not only des ribe how set and setq work but also illustrate how arguments are passed.

1.9.1 Using set To set the value of the symbol flowers to the list '(rose violet daisy butter up), evaluate the following expression by positioning the ursor after the expression and typing C-x C-e. (set 'flowers '(rose violet daisy butter up))

18

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) appears 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.2 Using setq As a pra ti al matter, you almost always quote the rst argument to set. The ombination of set and a quoted rst argument is so ommon that it has its own name: the spe ial form setq. This spe ial form is just like set ex ept that the rst argument is quoted automati ally, so you don't need to type the quote mark yourself. Also, as an added onvenien e, setq permits you to set several di erent variables to di erent values, all in one expression. To set the value of the variable arnivores to the list '(lion tiger leopard) using setq, the following expression is used: (setq arnivores '(lion tiger leopard))

This is exa tly the same as using set ex ept the rst argument is automati ally quoted by setq. (The `q' in setq means quote.)

Counting

19

With set, the expression would look like this: (set ' arnivores '(lion tiger leopard))

Also, setq an be used to assign di erent values to di erent variables. The rst argument is bound to the value of the se ond argument, the third argument is bound to the value of the fourth argument, and so on. For example, you ould use the following to assign a list of trees to the symbol trees and a list of herbivores to the symbol herbivores: (setq trees '(pine fir oak maple) herbivores '(gazelle antelope zebra))

(The expression ould just as well have been on one line, but it might not have t on a page; and humans nd it easier to read ni ely formatted lists.) Although I have been using the term `assign', there is another way of thinking about the workings of set and setq; and that is to say that set and setq make the symbol point to the list. This latter way of thinking is very ommon and in forth oming hapters we shall ome upon at least one symbol that has `pointer' as part of its name. The name is hosen be ause the symbol has a value, spe i ally a list, atta hed to it; or, expressed another way, the symbol is set to \point" to the list.

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.

(setq ounter (+ ounter 1))

; This is the in rementer.

ounter

; This is the ounter.

(The text following the `;' are omments. See Se tion 3.2.1, \Change a Fun tion De nition", page 32.) If you evaluate the rst of these expressions, the initializer, (setq

ounter 0), and then evaluate the third expression, ounter, the number 0 will appear in the e ho area. If you then evaluate the se ond expression, the in rementer, (setq ounter (+ ounter 1)), the ounter will get the value 1. So if you again evaluate ounter, the number 1 will appear in the e ho area. Ea h time you evaluate the se ond expression, the value of the ounter will be in remented. When you evaluate the in rementer, (setq ounter (+ ounter 1)), the Lisp interpreter rst evaluates the innermost list; this is the addition. In

20

Chapter 1: List Pro essing

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 quotation 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.

1.11 Exer ises A few simple exer ises:  Generate an error message by evaluating an appropriate symbol that is not within parentheses.

Exer ises

  

21

Generate an error message by evaluating an appropriate symbol that is between parentheses. Create a ounter that in rements by two rather than one. Write an expression that prints a message in the e ho area when evaluated.

22

Chapter 1: List Pro essing

Bu er Names

23

2 Pra ti ing Evaluation Before learning how to write a fun tion de nition in Ema s Lisp, it is useful to spend a little time evaluating various expressions that have already been written. These expressions will be lists with the fun tions as their rst (and often only) element. Sin e some of the fun tions asso iated with bu ers are both simple and interesting, we will start with those. In this se tion, we will evaluate a few of these. In another se tion, we will study the ode of several other bu er-related fun tions, to see how they were written. Whenever you give an editing ommand to Ema s Lisp, su h as the ommand to move the ursor or to s roll the s reen, you are evaluating an expression, the rst element of whi h is a fun tion. This is how Ema s works. When you type keys, you ause the Lisp interpreter to evaluate an expression and that is how you get your results. Even typing plain text involves evaluating an Ema s Lisp fun tion, in this ase, one that uses self-insert ommand, whi h simply inserts the hara ter you typed. The fun tions you evaluate by typing keystrokes are alled intera tive fun tions, or ommands; how you make a fun tion intera tive will be illustrated in the hapter on how to write fun tion de nitions. See Se tion 3.3, \Making a Fun tion Intera tive", page 33. In addition to typing keyboard ommands, we have seen a se ond way to evaluate an expression: by positioning the ursor after a list and typing C-x C-e. This is what we will do in the rest of this se tion. There are other ways to evaluate an expression as well; these will be des ribed as we ome to them. Besides being used for pra ti ing evaluation, the fun tions shown in the next few se tions are important in their own right. A study of these fun tions makes lear the distin tion between bu ers and les, how to swit h to a bu er, and how to determine a lo ation within it.

2.1 Bu er Names The two fun tions, buffer-name and buffer-file-name, show the di eren 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 evaluating (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 expressions, 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, \Variables", 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.

2.2 Getting Bu ers The buffer-name fun tion returns the name of the bu er; to get the bu er itself, a di erent fun tion is needed: the urrent-buffer fun tion. If you use this fun tion in ode, what you get is the bu er itself. A name and the obje t or entity to whi h the name refers are di erent from ea h other. You are not your name. You are a person to whom others refer by name. If you ask to speak to George and someone hands you a

ard with the letters `G', `e', `o', `r', `g', and `e' written on it, you might be amused, but you would not be satis ed. You do not want to speak to the name, but to the person to whom the name refers. A bu er is similar: the name of the s rat h bu er is `*s rat h*', but the name is not the bu er. To get a bu er itself, you need to use a fun tion su h as urrent-buffer. However, there is a slight ompli ation: if you evaluate urrent-buffer in an expression on its own, as we will do here, what you see is a printed representation of the name of the bu er without the ontents of the bu er. Ema s works this way for two reasons: the bu er may be thousands of lines long|too long to be onveniently displayed; and, another bu er may have the same ontents but a di erent name, and it is important to distinguish between them. Here is an expression ontaining the fun tion: ( urrent-buffer)

If you evaluate the expression in the usual way, `#' appears in the e ho area. The spe ial format indi ates that the bu er itself is being returned, rather than just its name. In identally, while you an type a number or symbol into a program, you

annot do that with the printed representation of a bu er: the only way to get a bu er itself is with a fun tion su h as urrent-buffer. A related fun tion is other-buffer. This returns the most re ently sele ted bu er other than the one you are in urrently. If you have re ently

26

Chapter 2: Pra ti ing Evaluation

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 `#' appear in the e ho area, or the name of whatever other bu er you swit hed ba k from most re ently1 .

2.3 Swit hing Bu ers The other-buffer fun tion a tually provides a bu er when it is used as an argument to a fun tion that requires one. We an see this by using other-buffer and swit h-to-buffer to swit h to a di erent bu er. But rst, a brief introdu tion to the swit h-to-buffer fun tion. When you swit hed ba k and forth from Info to the `*s rat h*' bu er to evaluate (buffer-name), you most likely typed C-x b and then typed `*s rat h*'2 when prompted in the minibu er for the name of the bu er to whi h you wanted to swit h. The keystrokes, C-x b, ause the Lisp interpreter to evaluate the intera tive fun tion swit h-to-buffer. As we said before, this is how Ema s works: di erent keystrokes all or run di erent fun tions. For example, C-f alls forward- har, M-e alls forward-senten e, and so on. By writing swit h-to-buffer in an expression, and giving it a bu er to swit h to, we an swit h bu ers just the way C-x b does. Here is the Lisp expression: (swit h-to-buffer (other-buffer))

The symbol swit h-to-buffer is the rst element of the list, so the Lisp interpreter will treat it as a fun tion and arry out the instru tions that are atta hed to it. But before doing that, the interpreter will note that other-buffer is inside parentheses and work on that symbol rst. otherbuffer is the rst (and in this ase, the only) element of this list, so the Lisp interpreter alls or runs the fun tion. It returns another bu er. Next, the interpreter runs swit h-to-buffer, passing to it, as an argument, the other bu er, whi h is what Ema s will swit h to. If you are reading this in Info, try this now. Evaluate the expression. (To get ba k, type C-x b hRETi.)3 1

2

3

A tually, by default, if the bu er from whi h you just swit hed is visible to you in another window, other-buffer will hoose the most re ent bu er that you annot see; this is a subtlety that I often forget. Or rather, to save typing, you probably typed just part of the name, su h as *s , and then pressed your TAB key to ause it to expand to the full name; and then typed your RET key. Remember, this expression will move you to your most re ent other bu er that you

annot see. If you really want to go to your most re ently sele ted bu er, even if you

an still see it, you need to evaluate the following more omplex expression: (swit h-to-buffer (other-buffer ( urrent-buffer) t))

Bu er Size and the Lo ation of Point

27

In the programming examples in later se tions of this do ument, you will see the fun tion set-buffer more often than swit h-to-buffer. This is be ause of a di eren e between omputer programs and humans: humans have eyes and expe t to see the bu er on whi h they are working on their

omputer terminals. This is so obvious, it almost goes without saying. However, programs do not have eyes. When a omputer program works on a bu er, that bu er does not need to be visible on the s reen. swit h-to-buffer is designed for humans and does two di erent things: it swit hes the bu er to whi h Ema s' attention is dire ted; and it swit hes the bu er displayed in the window to the new bu er. set-buffer, on the other hand, does only one thing: it swit hes the attention of the omputer program to a di erent bu er. The bu er on the s reen remains un hanged (of

ourse, normally nothing happens there until the ommand nishes running). Also, we have just introdu ed another jargon term, the word all. When you evaluate a list in whi h the rst symbol is a fun tion, you are alling that fun tion. The use of the term omes from the notion of the fun tion as an entity that an do something for you if you ` all' it|just as a plumber is an entity who an x a leak if you all him or her.

2.4 Bu er Size and the Lo ation of Point Finally, let's look at several rather simple fun tions, buffer-size, point, point-min, and point-max. These give information about the size of a bu er

and the lo ation of point within it. The fun tion buffer-size tells you the size of the urrent bu er; that is, the fun tion returns a ount of the number of hara ters in the bu er. (buffer-size)

You an evaluate this in the usual way, by positioning the ursor after the expression and typing C-x C-e. In Ema s, the urrent position of the ursor is alled point. The expression (point) returns a number that tells you where the ursor is lo ated as a ount of the number of hara ters from the beginning of the bu er up to point. You an see the hara ter ount for point in this bu er by evaluating the following expression in the usual way: (point)

As I write this, the value of point is 65724. The point fun tion is frequently used in some of the examples later in this book. In this ase, the rst argument to other-buffer tells it whi h bu er to skip|the

urrent one|and the se ond argument tells other-buffer it is OK to swit h to a visible bu er. In regular use, swit h-to-buffer takes you to an invisible window sin e you would most likely use C-x o (other-window) to go to another visible bu er.

28

Chapter 2: Pra ti ing Evaluation

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.

2.5 Exer ise Find a le with whi h you are working and move towards its middle. Find its bu er name, le name, length, and your position in the le.

The defun Spe ial Form

29

3 How To Write Fun tion De nitions When the Lisp interpreter evaluates a list, it looks to see whether the rst symbol on the list has a fun tion de nition atta hed to it; or, put another way, whether the symbol points to a fun tion de nition. If it does, the

omputer arries out the instru tions in the de nition. A symbol that has a fun tion de nition is alled, simply, a fun tion (although, properly speaking, the de nition is the fun tion and the symbol refers to it.) All fun tions are de ned in terms of other fun tions, ex ept for a few primitive fun tions that are written in the C programming language. When you write fun tions' de nitions, you will write them in Ema s Lisp and use other fun tions as your building blo ks. Some of the fun tions you will use will themselves be written in Ema s Lisp (perhaps by you) and some will be primitives written in C. The primitive fun tions are used exa tly like those written in Ema s Lisp and behave like them. They are written in C so we

an easily run GNU Ema s on any omputer that has suÆ ient power and

an run C. Let me re-emphasize this: when you write ode in Ema s Lisp, you do not distinguish between the use of fun tions written in C and the use of fun tions written in Ema s Lisp. The di eren e is irrelevant. I mention the distin tion only be ause it is interesting to know. Indeed, unless you investigate, you won't know whether an already-written fun tion is written in Ema s Lisp or C.

3.1 The defun Spe ial Form In Lisp, a symbol su h as mark-whole-buffer has ode atta hed to it that tells the omputer what to do when the fun tion is alled. This ode is alled the fun tion de nition and is reated by evaluating a Lisp expression that starts with the symbol defun (whi h is an abbreviation for de ne fun tion ). Be ause defun does not evaluate its arguments in the usual way, it is alled a spe ial form. In subsequent se tions, we will look at fun tion de nitions from the Ema s sour e ode, su h as mark-whole-buffer. In this se tion, we will des ribe a simple fun tion de nition so you an see how it looks. This fun tion de nition uses arithmeti be ause it makes for a simple example. Some people dislike examples using arithmeti ; however, if you are su h a person, do not despair. Hardly any of the ode we will study in the remainder of this introdu tion involves arithmeti or mathemati s. The examples mostly involve text in one way or another. A fun tion de nition has up to ve parts following the word defun: 1. The name of the symbol to whi h the fun tion de nition should be atta hed. 2. A list of the arguments that will be passed to the fun tion. If no arguments will be passed to the fun tion, this is an empty list, ().

30

Chapter 3: How To Write Fun tion De nitions

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 ) body ...)

; optional

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

de nition, you an hange the value of su h a symbol inside the body of a fun tion without hanging its value outside the fun tion. The e e t is similar to that produ ed by a let expression. (See Se tion 3.6, \let", page 36.) The argument list is followed by the do umentation string that des ribes the fun tion. This is what you see when you type C-h f and the name of a fun tion. In identally, when you write a do umentation string like this, you should make the rst line a omplete senten e sin e some ommands, su h as apropos, print only the rst line of a multi-line do umentation string. Also, you should not indent the se ond line of a do umentation string, if you have one, be ause that looks odd when you use C-h f (des ribe-fun tion). The do umentation string is optional, but it is so useful, it should be in luded in almost every fun tion you write. The third line of the example onsists of the body of the fun tion de nition. (Most fun tions' de nitions, of ourse, are longer than this.) In this fun tion, the body is the list, (* 7 number), whi h says to multiply the value of number by 7. (In Ema s Lisp, * is the fun tion for multipli ation, just as + is the fun tion for addition.) When you use the multiply-by-seven fun tion, the argument number evaluates to the a tual number you want used. Here is an example that shows how multiply-by-seven is used; but don't try to evaluate this yet! (multiply-by-seven 3)

The symbol number, spe i ed in the fun tion de nition in the next se tion, is given or \bound to" the value 3 in the a tual use of the fun tion. Note that although number was inside parentheses in the fun tion de nition, the argument passed to the multiply-by-seven fun tion is not in parentheses. The parentheses are written in the fun tion de nition so the omputer an gure out where the argument list ends and the rest of the fun tion de nition begins. If you evaluate this example, you are likely to get an error message. (Go ahead, try it!) This is be ause we have written the fun tion de nition, but not yet told the omputer about the de nition|we have not yet installed (or `loaded') the fun tion de nition in Ema s. Installing a fun tion is the pro ess that tells the Lisp interpreter the de nition of the fun tion. Installation is des ribed in the next se tion.

3.2 Install a Fun tion De nition If you are reading this inside of Info in Ema s, you an try out the

multiply-by-seven fun tion by rst evaluating the fun tion de nition and then evaluating (multiply-by-seven 3). A opy of the fun tion de nition

follows. Pla e the ursor after the last parenthesis of the fun tion de nition and type C-x C-e. When you do this, multiply-by-seven will appear in the e ho area. (What this means is that when a fun tion de nition is evaluated,

32

Chapter 3: How To Write Fun tion De nitions

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 forwardword 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, multiplyby-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.)

3.2.1 Change a Fun tion De nition If you want to hange the ode in multiply-by-seven, just rewrite it. To install the new version in pla e of the old one, evaluate the fun tion de nition again. This is how you modify ode in Ema s. It is very simple. As an example, you an hange the multiply-by-seven fun tion to add the number to itself seven times instead of multiplying the number by seven. It produ es the same answer, but by a di erent path. At the same time, we will add a omment to the ode; a omment is text that the Lisp interpreter ignores, but that a human reader may nd useful or enlightening. The

omment is that this is the \se ond version". (defun multiply-by-seven (number) ; Se ond version. "Multiply NUMBER by seven." (+ number number number number number number number))

The omment follows a semi olon, `;'. In Lisp, everything on a line that follows a semi olon is a omment. The end of the line is the end of the

omment. To stret h a omment over two or more lines, begin ea h line with a semi olon. See Se tion 16.3, \Beginning a `.ema s' File", page 216, and se tion \Comments" in The GNU Ema s Lisp Referen e Manual, for more about

omments.

Make a Fun tion Intera tive

33

You an install this version of the multiply-by-seven fun tion by evaluating it in the same way you evaluated the rst fun tion: pla e the ursor after the last parenthesis and type C-x C-e. In summary, this is how you write ode in Ema s Lisp: you write a fun tion; install it; test it; and then make xes or enhan ements and install it again.

3.3 Make a Fun tion Intera tive You make a fun tion intera tive by pla ing a list that begins with the spe ial form intera tive immediately after the do umentation. A user

an invoke an intera tive fun tion by typing M-x and then the name of the fun tion; or by typing the keys to whi h it is bound, for example, by typing C-n for next-line or C-x h for mark-whole-buffer. Interestingly, when you all an intera tive fun tion intera tively, the value returned is not automati ally displayed in the e ho area. This is be ause you often all an intera tive fun tion for its side e e ts, su h as moving forward by a word or line, and not for the value returned. If the returned value were displayed in the e ho area ea h time you typed a key, it would be very distra ting. Both the use of the spe ial form intera tive and one way to display a value in the e ho area an be illustrated by reating an intera tive version of multiply-by-seven. Here is the ode: (defun multiply-by-seven (number) ; Intera tive version. "Multiply NUMBER by seven." (intera tive "p") (message "The result is %d" (* 7 number)))

You an install this ode by pla ing your ursor after it and typing C-x C-e. The name of the fun tion will appear in your e ho area. Then, you an use this ode by typing C-u and a number and then typing M-x multiply-byseven and pressing hRETi. The phrase `The result is ...' followed by the produ t will appear in the e ho area. Speaking more generally, you invoke a fun tion like this in either of two ways: 1. By typing a pre x argument that ontains the number to be passed, and then typing M-x and the name of the fun tion, as with C-u 3 M-x forward-senten e; or, 2. By typing whatever key or key hord the fun tion is bound to, as with C-u 3 M-e. Both the examples just mentioned work identi ally to move point forward three senten es. (Sin e multiply-by-seven is not bound to a key, it ould not be used as an example of key binding.)

34

Chapter 3: How To Write Fun tion De nitions

(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 Cu and then a number, for example, C-u 3 M-e (if you type C-u without a number, it defaults to 4).

3.3.1 An Intera tive multiply-by-seven Let's look at the use of the spe ial form intera tive and then at the fun tion message in the intera tive version of multiply-by-seven. You will re all that the fun tion de nition looks like this: (defun multiply-by-seven (number) ; Intera tive version. "Multiply NUMBER by seven." (intera tive "p") (message "The result is %d" (* 7 number)))

In this fun tion, the expression, (intera tive "p"), is a list of two elements. The "p" tells Ema s to pass the pre x argument to the fun tion and use its value for the argument of the fun tion. The argument will be a number. This means that the symbol number will be bound to a number in the line: (message "The result is %d" (* 7 number))

For example, if your pre x argument is 5, the Lisp interpreter will evaluate the line as if it were: (message "The result is %d" (* 7 5))

(If you are reading this in GNU Ema s, you an evaluate this expression yourself.) First, the interpreter will evaluate the inner list, whi h is (* 7 5). This returns a value of 35. Next, it will evaluate the outer list, passing the values of the se ond and subsequent elements of the list to the fun tion message. As we have seen, message is an Ema s Lisp fun tion espe ially designed for sending a one line message to a user. (See Se tion 1.8.5, \The message fun tion", page 16.) In summary, the message fun tion prints its rst argument in the e ho area as is, ex ept for o

urren es of `%d', `%s', or `% '. When it sees one of these ontrol sequen es, the fun tion looks to the se ond and subsequent arguments and prints the value of the argument in the lo ation in the string where the ontrol sequen e is lo ated. In the intera tive multiply-by-seven fun tion, the ontrol string is `%d', whi h requires a number, and the value returned by evaluating (* 7 5) is the number 35. Consequently, the number 35 is printed in pla e of the `%d' and the message is `The result is 35'. (Note that when you all the fun tion multiply-by-seven, the message is printed without quotes, but when you all message, the text is printed in double quotes. This is be ause the value returned by message is what

Di erent Options for intera tive

35

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.)

3.4 Di erent Options for intera tive In the example, multiply-by-seven used "p" as the argument to intera tive. This argument told Ema s to interpret your typing either C-u followed by a number or hMETAi followed by a number as a ommand

to pass that number to the fun tion as its argument. Ema s has more than twenty hara ters prede ned for use with intera tive. In almost every

ase, one of these options will enable you to pass the right information intera tively to a fun tion. (See se tion \Code Chara ters for intera tive" in The GNU Ema s Lisp Referen e Manual.) For example, the hara ter `r' auses Ema s to pass the beginning and end of the region (the urrent values of point and mark) to the fun tion as two separate arguments. It is used as follows: (intera tive "r")

On the other hand, a `B' tells Ema s to ask for the name of a bu er that will be passed to the fun tion. When it sees a `B', Ema s will ask for the name by prompting the user in the minibu er, using a string that follows the `B', as in "BAppend to buffer: ". Not only will Ema s prompt for the name, but Ema s will omplete the name if you type enough of it and press hTABi. A fun tion with two or more arguments an have information passed to ea h argument by adding parts to the string that follows intera tive. When you do this, the information is passed to ea h argument in the same order it is spe i ed in the intera tive list. In the string, ea h part is separated from the next part by a `\n', whi h is a newline. For example, you ould follow "BAppend to buffer: " with a `\n') and an `r'. This would

ause Ema s to pass the values of point and mark to the fun tion as well as prompt you for the bu er|three arguments in all. In this ase, the fun tion de nition would look like the following, where buffer, start, and end are the symbols to whi h intera tive binds the bu er and the urrent values of the beginning and ending of the region: (defun name-of-fun tion (buffer start end) "do umentation..." (intera tive "BAppend to buffer: \nr") body-of-fun tion...)

(The spa e after the olon in the prompt makes it look better when you are prompted. The append-to-buffer fun tion looks exa tly like this. See Se tion 4.4, \The De nition of append-to-buffer", page 56.)

36

Chapter 3: How To Write Fun tion De nitions

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.5 Install Code Permanently When you install a fun tion de nition by evaluating it, it will stay installed until you quit Ema s. The next time you start a new session of Ema s, the fun tion will not be installed unless you evaluate the fun tion de nition again. At some point, you may want to have ode installed automati ally whenever you start a new session of Ema s. There are several ways of doing this:  If you have ode that is just for yourself, you an put the ode for the fun tion de nition in your `.ema s' initialization le. When you start Ema s, your `.ema s' le is automati ally evaluated and all the fun tion de nitions within it are installed. See Chapter 16, \Your `.ema s' File", page 213.  Alternatively, you an put the fun tion de nitions that you want installed in one or more les of their own and use the load fun tion to

ause Ema s to evaluate and thereby install ea h of the fun tions in the les. See Se tion 16.9, \Loading Files", page 222.  On the other hand, if you have ode that your whole site will use, it is usual to put it in a le alled `site-init.el' that is loaded when Ema s is built. This makes the ode available to everyone who uses your ma hine. (See the `INSTALL' le that is part of the Ema s distribution.) Finally, if you have ode that everyone who uses Ema s may want, you

an post it on a omputer network or send a opy to the Free Software Foundation. (When you do this, please li ense the ode and its do umentation under a li ense that permits other people to run, opy, study, modify, and redistribute the ode and whi h prote ts you from having your work taken from you.) If you send a opy of your ode to the Free Software Foundation, and properly prote t yourself and others, it may be in luded in the next release of Ema s. In large part, this is how Ema s has grown over the past years, by donations.

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

let is used to atta h or bind a symbol to a value in su h a way that the Lisp interpreter will not onfuse the variable with a variable of the same name that is not part of the fun tion. To understand why the let spe ial form is ne essary, onsider the situation in whi h you own a home that you generally refer to as `the house', as in the senten e, \The house needs painting." If you are visiting a friend and your host refers to `the house', he is likely to be referring to his house, not yours, that is, to a di erent house. If your friend is referring to his house and you think he is referring to your house, you may be in for some onfusion. The same thing ould happen in Lisp if a variable that is used inside of one fun tion has the same name as a variable that is used inside of another fun tion, and the two are not intended to refer to the same value. The let spe ial form prevents this kind of onfusion. The let spe ial form prevents onfusion. let reates a name for a lo al variable that overshadows any use of the same name outside the let expression. This is like understanding that whenever your host refers to `the house', he means his house, not yours. (Symbols used in argument lists work the same way. See Se tion 3.1, \The defun Spe ial Form", page 29.) Lo al variables reated by a let expression retain their value only within the let expression itself (and within expressions alled within the let expression); the lo al variables have no e e t outside the let expression. Another way to think about let is that it is like a setq that is temporary and lo al. The values set by let are automati ally undone when the let is nished. The setting only e e ts expressions that are inside the bounds of the let expression. In omputer s ien e jargon, we would say \the binding of a symbol is visible only in fun tions alled in the let form; in Ema s Lisp, s oping is dynami , not lexi al." let an reate more than one variable at on e. Also, let gives ea h variable it reates an initial value, either a value spe i ed by you, or nil. (In the jargon, this is alled `binding the variable to the value'.) After let has reated and bound the variables, it exe utes the ode in the body of the let, and returns the value of the last expression in the body, as the value of the whole let expression. (`Exe ute' is a jargon term that means to evaluate a list; it omes from the use of the word meaning `to give pra ti al e e t to' (Oxford English Di tionary). Sin e you evaluate an expression to perform an a tion, `exe ute' has evolved as a synonym to `evaluate'.)

3.6.1 The Parts of a let Expression A let expression is a list of three parts. The rst part is the symbol let. The se ond part is a list, alled a varlist, ea h element of whi h is

either a symbol by itself or a two-element list, the rst element of whi h is a symbol. The third part of the let expression is the body of the let. The body usually onsists of one or more lists.

38

Chapter 3: How To Write Fun tion De nitions A template for a let expression looks like this: (let varlist body ...)

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 ...)

3.6.2 Sample let Expression The following expression reates and gives initial values to the two variables zebra and tiger. The body of the let expression is a list whi h alls the message fun tion. (let ((zebra 'stripes) (tiger 'fier e)) (message "One kind of animal has %s and another is %s." zebra tiger))

Here, the varlist is ((zebra 'stripes) (tiger 'fier e)). The two variables are zebra and tiger. Ea h variable is the rst element of a two-element list and ea h value is the se ond element of its two-element list. In the varlist, Ema s binds the variable zebra to the value stripes, and binds the variable tiger to the value fier e. In this example, both values are symbols pre eded by a quote. The values ould just as well have been another list or a string. The body of the let follows after the list holding the variables. In this example, the body is a list that uses the message fun tion to print a string in the e ho area.

The if Spe ial Form

39

You may evaluate the example in the usual fashion, by pla ing the ursor 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'.

3.6.3 Uninitialized Variables in a let Statement If you do not bind the variables in a let statement to spe i initial values, they will automati ally be bound to an initial value of nil, as in the following expression: (let ((bir h 3) pine fir (oak 'some)) (message "Here are %d variables with %s, %s, and %s value." bir h pine fir oak))

Here, the varlist is ((bir h 3) pine fir (oak 'some)). If you evaluate this expression in the usual way, the following will appear in your e ho area: "Here are 3 variables with nil, nil, and some value."

In this example, Ema s binds the symbol bir h to the number 3, binds the symbols pine and fir to nil, and binds the symbol oak to the value some. Note that in the rst part of the let, the variables pine and fir stand alone as atoms that are not surrounded by parentheses; this is be ause they are being bound to nil, the empty list. But oak is bound to some and so is a part of the list (oak 'some). Similarly, bir h is bound to the number 3 and so is in a list with that number. (Sin e a number evaluates to itself, the number does not need to be quoted. Also, the number is printed in the message using a `%d' rather than a `%s'.) The four variables as a group are put into a list to delimit them from the body of the let.

3.7 The if Spe ial Form A third spe ial form, in addition to defun and let, is the onditional if. This form is used to instru t the omputer to make de isions. You an write fun tion de nitions without using if, but it is used often enough, and is important enough, to be in luded here. It is used, for example, in the ode for the fun tion beginning-of-buffer.

40

Chapter 3: How To Write Fun tion De nitions

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) (message "5 is greater than 4!"))

; if-part ; 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.

3.7.1 The type-of-animal Fun tion in Detail Let's look at the type-of-animal fun tion in detail. The fun tion de nition for type-of-animal was written by lling the slots of two templates, one for a fun tion de nition as a whole, and a se ond for an if expression. The template for every fun tion that is not intera tive is: (defun name-of-fun tion (argument-list) "do umentation..." body ...)

The parts of the fun tion that mat h this template look like this: (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." body: the if expression)

The name of fun tion is type-of-animal; it is passed the value of one argument. The argument list is followed by a multi-line do umentation string. The do umentation string is in luded in the example be ause it is a good habit to write do umentation string for every fun tion de nition. The body of the fun tion de nition onsists of the if expression. The template for an if expression looks like this: (if true-or-false-test

a tion-to- arry-out-if-the-test-returns-true )

In the type-of-animal fun tion, the ode for the if looks like this: (if (equal hara teristi 'fier e) (message "It's a tiger!")))

Here, the true-or-false-test is the expression: (equal hara teristi 'fier e)

In Lisp, equal is a fun tion that determines whether its rst argument is equal to its se ond argument. The se ond argument is the quoted symbol

42

Chapter 3: How To Write Fun tion De nitions

'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 argument 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.

3.8 If{then{else Expressions An if expression may have an optional third argument, alled the elsepart, for the ase when the true-or-false-test returns false. When this happens, the se ond argument or then-part of the overall if expression is not evaluated, but the third or else-part is evaluated. You might think of this as the loudy day alternative for the de ision `if it is warm and sunny, then go to the bea h, else read a book!". The word \else" is not written in the Lisp ode; the else-part of an if expression omes after the then-part. In the written Lisp, the else-part is usually written to start on a line of its own and is indented less than the then-part: (if true-or-false-test

a tion-to- arry-out-if-the-test-returns-true a tion-to- arry-out-if-the-test-returns-false )

For example, the following if expression prints the message `4 is not greater than 5!' when you evaluate it in the usual way: (if (> 4 5) ; if-part (message "5 is greater than 4!") ; then-part (message "4 is not greater than 5!")) ; else-part

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 automati 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.)

3.9 Truth and Falsehood in Ema s Lisp There is an important aspe t to the truth test in an if expression. So far, we have spoken of `true' and `false' as values of predi ates as if they were new kinds of Ema s Lisp obje ts. In fa t, `false' is just our old friend nil. Anything else|anything at all|is `true'. The expression that tests for truth is interpreted as true if the result of evaluating it is a value that is not nil. In other words, the result of the test is onsidered true if the value returned is a number su h as 47, a string su h as "hello", or a symbol (other than nil) su h as flowers, or a list, or even a bu er! Before illustrating a test for truth, we need an explanation of nil. In Ema s Lisp, the symbol nil has two meanings. First, it means the empty list. Se ond, it means false and is the value returned when a true-orfalse-test tests false. nil an be written as an empty list, (), or as nil. As far as the Lisp interpreter is on erned, () and nil are the same. Humans, however, tend to use nil for false and () for the empty list. In Ema s Lisp, any value that is not nil|is not the empty list|is onsidered true. This means that if an evaluation returns something that is not

44

Chapter 3: How To Write Fun tion De nitions

an empty list, an if expression will test true. For example, if a number is put in the slot for the test, it will be evaluated and will return itself, sin e that is what numbers do when evaluated. In this onditional, the if expression will test true. The expression tests false only when nil, an empty list, is returned by evaluating the expression. You an see this by evaluating the two expressions in the following examples. In the rst example, the number 4 is evaluated as the test in the if expression and returns itself; onsequently, the then-part of the expression is evaluated and returned: `true' appears in the e ho area. In the se ond example, the nil indi ates false; onsequently, the else-part of the expression is evaluated and returned: `false' appears in the e ho area. (if 4 'true 'false) (if nil 'true 'false)

In identally, if some other useful value is not available for a test that returns true, then the Lisp interpreter will return the symbol t for true. For example, the expression (> 5 4) returns t when evaluated, as you an see by evaluating it in the usual way: (> 5 4)

On the other hand, this fun tion returns nil if the test is false. (> 4 5)

3.10

save-ex ursion

The save-ex ursion fun tion is the fourth and nal spe ial form that we will dis uss in this hapter. In Ema s Lisp programs used for editing, the save-ex ursion fun tion is very ommon. It saves the lo ation of point and mark, exe utes the body of the fun tion, and then restores point and mark to their previous positions if their lo ations were hanged. Its primary purpose is to keep the user from being surprised and disturbed by unexpe ted movement of point or mark. Before dis ussing save-ex ursion, however, it may be useful rst to review what point and mark are in GNU Ema s. Point is the urrent lo ation of the ursor. Wherever the ursor is, that is point. More pre isely, on terminals where the ursor appears to be on top of a hara ter, point is immediately before the hara ter. In Ema s Lisp, point is an integer. The rst hara ter in a bu er is number one, the se ond is number two, and so on. The fun tion point returns the urrent position of the ursor as a number. Ea h bu er has its own value for point.

Template for a save-ex ursion Expression

45

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. Numerous ommands work on the region, in luding enter-region, ountlines-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 workings even though a user would not expe t this. For example, ount-linesregion 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, saveex 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 appendto-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

defun

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. 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 Common ode hara ters are: b

The name of an existing bu er.

f

The name of an existing le.

p

The numeri pre x argument. (Note that this `p' is lower ase.)

r

Point and the mark, as two numeri arguments, smallest rst. This is the only ode letter that spe i es two su

essive arguments rather than one.

See se tion \Code Chara ters for `intera tive'" in The GNU Ema s Lisp Referen e Manual, for a omplete list of ode hara ters. let

De lare that a list of variables is for use within the body of the

let and give them an initial value, either nil or a spe i ed

value; then evaluate the rest of the expressions in the body of the let and return the value of the last one. Inside the body of the let, the Lisp interpreter does not see the values of the variables of the same names that are bound outside of the let. For example, (let ((foo (buffer-name)) (bar (buffer-size))) (message "This buffer is %s and has %d hara ters." foo bar))

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))))

if

Evaluate the rst argument to the fun tion; if it is true, evaluate the se ond argument; else evaluate the third argument, if there is one. The if spe ial form is alled a onditional. There are other onditionals in Ema s Lisp, but if is perhaps the most ommonly used.

48

Chapter 3: How To Write Fun tion De nitions 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

message

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 <=. 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 setq set

49 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

point-min

point-max

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. Return the minimum permissible value of point in the urrent bu er. This is 1, unless narrowing is in e e t. 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

3.12 Exer ises 



Write a non-intera tive fun tion that doubles the value of its argument, a number. Make that fun tion intera tive. Write a fun tion that tests whether the urrent value of fill- olumn is greater than the argument passed to the fun tion, and if so, prints an appropriate message.

Finding More Information

51

4 A Few Bu er{Related Fun tions In this hapter we study in detail several of the fun tions used in GNU Ema s. This is alled a \walk-through". These fun tions are used as examples of Lisp ode, but are not imaginary examples; with the ex eption of the rst, simpli ed fun tion de nition, these fun tions show the a tual ode used in GNU Ema s. You an learn a great deal from these de nitions. The fun tions des ribed here are all related to bu ers. Later, we will study other fun tions.

4.1 Finding More Information In this walk-through, I will des ribe ea h new fun tion as we ome to it, sometimes in detail and sometimes brie y. If you are interested, you an get the full do umentation of any Ema s Lisp fun tion at any time by typing C-h f and then the name of the fun tion (and then hRETi). Similarly, you

an get the full do umentation for a variable by typing C-h v and then the name of the variable (and then hRETi). In versions 20 and higher, when a fun tion is written in Ema s Lisp, des ribe-fun tion will also tell you the lo ation of the fun tion de nition. If you move point over the le name and press the hRETi key, whi h is this

ase means help-follow rather than `return' or `enter', Ema s will take you dire tly to the fun tion de nition. More generally, if you want to see a fun tion in its original sour e le, you an use the find-tags fun tion to jump to it. find-tags works with a wide variety of languages, not just Lisp, and C, and it works with nonprogramming text as well. For example, find-tags will jump to the various nodes in the Texinfo sour e le of this do ument. The find-tags fun tion depends on `tags tables' that re ord the lo ations of the fun tions, variables, and other items to whi h find-tags jumps. To use the find-tags ommand, type M-. (i.e., type the hMETAi key and the period key at the same time, or else type the hESCi key and then type the period key), and then, at the prompt, type in the name of the fun tion whose sour e ode you want to see, su h as mark-whole-buffer, and then type hRETi. Ema s will swit h bu ers and display the sour e ode for the fun tion on your s reen. To swit h ba k to your urrent bu er, type C-x b hRETi. (On some keyboards, the hMETAi key is labelled hALTi.) Depending on how the initial default values of your opy of Ema s are set, you may also need to spe ify the lo ation of your `tags table', whi h is a le alled `TAGS'. For example, if you are interested in Ema s sour es, the tags table you will most likely want, if it has already been reated for you, will be in a subdire tory of the `/usr/lo al/share/ema s/' dire tory; thus you would use the M-x visit-tags-table ommand and spe ify a pathname su h as `/usr/lo al/share/ema s/21.0.100/lisp/TAGS'

52

Chapter 4: A Few Bu er{Related Fun tions

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."

4.2 A Simpli ed beginning-of-buffer De nition The beginning-of-buffer ommand is a good fun tion to start with sin e you are likely to be familiar with it and it is easy to understand. Used as an intera tive ommand, beginning-of-buffer moves the ursor to the beginning of the bu er, leaving the mark at the previous position. It is generally bound to M-<. In this se tion, we will dis uss a shortened version of the fun tion that shows how it is most frequently used. This shortened fun tion works as written, but it does not ontain the ode for a omplex option. In another se tion, we will des ribe the entire fun tion. (See Se tion 5.3, \Complete De nition of beginning-of-buffer", page 69.) Before looking at the ode, let's onsider what the fun tion de nition has to ontain: it must in lude an expression that makes the fun tion intera tive so it an be alled by typing M-x beginning-of-buffer or by typing a key hord su h as C-<; it must in lude ode to leave a mark at the original position in the bu er; and it must in lude ode to move the ursor to the beginning of the bu er.

A Simpli ed beginning-of-buffer De nition

53

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 expression 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*' window. 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)).

4.3 The De nition of mark-whole-buffer The mark-whole-buffer fun tion is no harder to understand than the simplified-beginning-of-buffer fun tion. In this ase, however, we will

look at the omplete fun tion, not a shortened version. The mark-whole-buffer fun tion is not as ommonly used as the beginning-of-buffer fun tion, but is useful nonetheless: it marks a whole bu er as a region by putting point at the beginning and a mark at the end of the bu er. It is generally bound to C-x h. In GNU Ema s 20, the ode for the omplete fun tion looks like this: (defun mark-whole-buffer () "Put point at beginning and mark at end of buffer." (intera tive) (push-mark (point)) (push-mark (point-max)) (goto- har (point-min)))

Like all other fun tions, the mark-whole-buffer fun tion ts into the template for a fun tion de nition. The template looks like this: (defun name-of-fun tion (argument-list) "do umentation..." (intera tive-expression...) body ...)

Here is how the fun tion works: the name of the fun tion is mark-wholebuffer; it is followed by an empty argument list, `()', whi h means that the

fun tion does not require arguments. The do umentation omes next. The next line is an (intera tive) expression that tells Ema s that the fun tion will be used intera tively. These details are similar to the simplified-beginning-of-buffer fun tion des ribed in the previous se tion.

Body of mark-whole-buffer

55

4.3.1 Body of mark-whole-buffer The body of the mark-whole-buffer fun tion onsists of three lines of

ode: (push-mark (point)) (push-mark (point-max)) (goto- har (point-min))

The rst of these lines is the expression, (push-mark (point)). This line does exa tly the same job as the rst line of the body of the simplified-beginning-of-buffer fun tion, whi h is written (pushmark). In both ases, the Lisp interpreter sets a mark at the urrent position of the ursor. I don't know why the expression in mark-whole-buffer is written (pushmark (point)) and the expression in beginning-of-buffer is written (push-mark). Perhaps whoever wrote the ode did not know that the arguments for push-mark are optional and that if push-mark is not passed an argument, the fun tion automati ally sets mark at the lo ation of point by default. Or perhaps the expression was written so as to parallel the stru ture of the next line. In any ase, the line auses Ema s to determine the position of point and set a mark there. The next line of mark-whole-buffer is (push-mark (point-max). This expression sets a mark at the point in the bu er that has the highest number. This will be the end of the bu er (or, if the bu er is narrowed, the end of the a

essible portion of the bu er. See Chapter 6, \Narrowing and Widening", page 77, for more about narrowing.) After this mark has been set, the previous mark, the one set at point, is no longer set, but Ema s remembers its position, just as all other re ent marks are always remembered. This means that you an, if you wish, go ba k to that position by typing C-u C-hSPCi twi e. (In GNU Ema s 21, the (push-mark (point-max) is slightly more ompli ated than shown here. The line reads (push-mark (point-max) nil t)

(The expression works nearly the same as before. It sets a mark at the highest numbered pla e in the bu er that it an. However, in this version, push-mark has two additional arguments. The se ond argument to pushmark is nil. This tells the fun tion it should display a message that says `Mark set' when it pushes the mark. The third argument is t. This tells push-mark to a tivate the mark when Transient Mark mode is turned on. Transient Mark mode highlights the urrently a tive region. It is usually turned o .) Finally, the last line of the fun tion is (goto- har (point-min))). This is written exa tly the same way as it is written in beginning-of-buffer. The expression moves 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

56

Chapter 4: A Few Bu er{Related Fun tions

of the bu er). As a result of this, point is pla ed at the beginning of the bu er and mark is set at the end of the bu er. The whole bu er is, therefore, the region.

4.4 The De nition of append-to-buffer The append-to-buffer ommand is very nearly as simple as the markwhole-buffer ommand. What it does is opy the region (that is, the part

of the bu er between point and mark) from the urrent bu er to a spe i ed bu er. The append-to-buffer ommand uses the insert-buffer-substring fun tion to opy the region. insert-buffer-substring is des ribed by its name: it takes a string of hara ters from part of a bu er, a \substring", and inserts them into another bu er. Most of append-to-buffer is on erned with setting up the onditions for insert-buffer-substring to work: the

ode must spe ify both the bu er to whi h the text will go and the region that will be opied. Here is the omplete text of the fun tion: (defun append-to-buffer (buffer start end) "Append to spe ified buffer the text of the region. It is inserted into that buffer before its point. When alling from a program, give three arguments: a buffer or the name of one, and two hara ter numbers spe ifying the portion of the urrent buffer to be opied." (intera tive "BAppend to buffer: \nr") (let ((oldbuf ( urrent-buffer))) (save-ex ursion (set-buffer (get-buffer- reate buffer)) (insert-buffer-substring oldbuf start end))))

The fun tion an be understood by looking at it as a series of lled-in templates. The outermost template is for the fun tion de nition. In this fun tion, it looks like this (with several slots lled in): (defun append-to-buffer (buffer start end) "do umentation..." (intera tive "BAppend to buffer: \nr") body ...)

The rst line of the fun tion in ludes its name and three arguments. The arguments are the buffer to whi h the text will be opied, and the start and end of the region in the urrent bu er that will be opied. The next part of the fun tion is the do umentation, whi h is lear and

omplete.

The Body of append-to-buffer

57

4.4.1 The append-to-buffer Intera tive Expression Sin e the append-to-buffer fun tion will be used intera tively, the fun tion must have an intera tive expression. (For a review of intera tive, see Se tion 3.3, \Making a Fun tion Intera tive", page 33.) The expression reads as follows: (intera tive "BAppend to buffer: \nr")

This expression has an argument inside of quotation marks and that argument has two parts, separated by `\n'. The rst part is `BAppend to buffer: '. Here, the `B' tells Ema s to ask for the name of the bu er that will be passed to the fun tion. Ema s will ask for the name by prompting the user in the minibu er, using the string following the `B', whi h is the string `Append to buffer: '. Ema s then binds the variable buffer in the fun tion's argument list to the spe i ed bu er. The newline, `\n', separates the rst part of the argument from the se ond part. It is followed by an `r' that tells Ema s to bind the two arguments that follow the symbol buffer in the fun tion's argument list (that is, start and end) to the values of point and mark.

4.4.2 The Body of append-to-buffer The body of the append-to-buffer fun tion begins with let. As we have seen before (see Se tion 3.6, \let", page 36), the purpose of a let expression is to reate and give initial values to one or more variables that will only be used within the body of the let. This means that su h a variable will not be onfused with any variable of the same name outside the let expression. We an see how the let expression ts into the fun tion as a whole by showing a template for append-to-buffer with the let expression in outline: (defun append-to-buffer (buffer start end) "do umentation..." (intera tive "BAppend to buffer: \nr") (let ((variable value )) body ...)

The let expression has three elements: 1. The symbol let; 2. A varlist ontaining, in this ase, a single two-element list, (variable value ); 3. The body of the let expression.

58

Chapter 4: A Few Bu er{Related Fun tions In the append-to-buffer fun tion, the varlist looks like this: (oldbuf ( urrent-buffer))

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)).

4.4.3

save-ex ursion

in append-to-buffer

The body of the let expression in append-to-buffer onsists of a saveex ursion expression. The save-ex ursion fun tion saves the lo ations of point and mark, and restores them to those positions after the expressions in the body of the save-ex ursion omplete exe ution. In addition, save-ex ursion keeps tra k of the original bu er, and restores it. This is how save-ex ursion is used in append-to-buffer. In identally, it is worth noting here that a Lisp fun tion is normally formatted so that everything that is en losed in a multi-line spread is indented more to the right than the rst symbol. In this fun tion de nition, the let is indented more than the defun, and the save-ex ursion is indented more than the let, like this: (defun ... ... ... (let... (save-ex ursion ...

save-ex ursion in append-to-buffer

59

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 expressions. 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 )

hange-ba k-to-original-bu er-when- nished let-the-lo al-meaning-of-oldbuf-disappear-when- nished

In summary, append-to-buffer works as follows: it saves the value of the

urrent bu er in the variable alled oldbuf. It gets the new bu er, reating one if need be, and swit hes Ema s to it. Using the value of oldbuf, it inserts the region of text from the old bu er into the new bu er; and then using save-ex ursion, it brings you ba k to your original bu er. In looking at append-to-buffer, you have explored a fairly omplex fun tion. It shows how to use let and save-ex ursion, and how to hange to and ome ba k from another bu er. Many fun tion de nitions use let, save-ex ursion, and set-buffer this way.

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. Conventionally 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

goto- har

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. 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.

4.6 Exer ises 

 

Write your own simplified-end-of-buffer fun tion de nition; then test it to see whether it works. Use if and get-buffer to write a fun tion that prints a message telling you whether a bu er exists. Using find-tag, nd the sour e for the opy-to-buffer fun tion.

62

Chapter 4: A Few Bu er{Related Fun tions

The De nition of opy-to-buffer

63

5 A Few More Complex Fun tions In this hapter, we build on what we have learned in previous hapters by looking at more omplex fun tions. The opy-to-buffer fun tion illustrates use of two save-ex ursion expressions in one de nition, while the insertbuffer fun tion illustrates use of an asterisk in an intera tive expression, use of or, and the important distin tion between a name and the obje t to whi h the name refers.

5.1 The De nition of opy-to-buffer After understanding how append-to-buffer works, it is easy to understand opy-to-buffer. This fun tion opies text into a bu er, but instead of adding to the se ond bu er, it repla es the previous text in the se ond bu er. The ode for the opy-to-buffer fun tion is almost the same as the ode for append-to-buffer, ex ept that erase-buffer and a se ond save-ex ursion are used. (See Se tion 4.4, \The De nition of append-to-buffer", page 56, for the des ription of append-to-buffer.) The body of opy-to-buffer looks like this ... (intera tive "BCopy to buffer: \nr") (let ((oldbuf ( urrent-buffer))) (save-ex ursion (set-buffer (get-buffer- reate buffer)) (erase-buffer) (save-ex ursion (insert-buffer-substring oldbuf start end)))))

This ode is similar to the ode in append-to-buffer: it is only after

hanging to the bu er to whi h the text will be opied that the de nition for this fun tion diverges from the de nition for append-to-buffer: the

opy-to-buffer fun tion erases the bu er's former ontents. (This is what is meant by `repla ement'; to repla e text, Ema s erases the previous text and then inserts new text.) After erasing the previous ontents of the bu er, save-ex ursion is used for a se ond time and the new text is inserted. Why is save-ex ursion used twi e? Consider again what the fun tion does. In outline, the body of opy-to-buffer looks like this: (let (bind-oldbuf-to-value-of- urrent-buffer) (save-ex ursion ; First use of save-ex ursion.

hange-bu er

(erase-buffer) (save-ex ursion

; Se ond use of save-ex ursion. insert-substring-from-oldbuf-into-bu er )))

64

Chapter 5: A Few More Complex Fun tions

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 appendto-buffer. Why the se ond use? The reason is that insert-buffersubstring 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.)

5.2 The De nition of insert-buffer insert-buffer is yet another bu er-related fun tion. This ommand

opies another bu er into the urrent bu er. It is the reverse of appendto-buffer or opy-to-buffer, sin e they opy a region of text from the

urrent bu er to another bu er. In addition, this ode illustrates the use of intera tive with a bu er that might be read-only and the important distin tion between the name of an obje t and the obje t a tually referred to. Here is the ode: (defun insert-buffer (buffer) "Insert after point the ontents of BUFFER. Puts mark after the inserted text. BUFFER may be a buffer or a buffer name." (intera tive "*bInsert buffer: ") (or (bufferp buffer) (setq buffer (get-buffer buffer))) (let (start end newmark) (save-ex ursion (save-ex ursion (set-buffer buffer) (setq start (point-min) end (point-max))) (insert-buffer-substring buffer start end) (setq newmark (point))) (push-mark newmark)))

As with other fun tion de nitions, you an use a template to see an outline of the fun tion: (defun insert-buffer (buffer) "do umentation..." (intera tive "*bInsert buffer: ") body ...)

The Body of the insert-buffer Fun tion

65

5.2.1 The Intera tive Expression in insert-buffer In insert-buffer, the argument to the intera tive de laration has two parts, an asterisk, `*', and `bInsert buffer: '.

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.

`b' in an Intera tive Expression The next argument in the intera tive expression starts with a lower ase `b'. (This is di erent from the ode for append-to-buffer, whi h uses an upper- ase `B'. See Se tion 4.4, \The De nition of append-to-buffer", page 56.) The lower- ase `b' tells the Lisp interpreter that the argument for insert-buffer should be an existing bu er or else its name. (The upper ase `B' option provides for the possibility that the bu er does not exist.) Ema s will prompt you for the name of the bu er, o ering you a default bu er, with name ompletion enabled. If the bu er does not exist, you re eive a message that says \No mat h"; your terminal may beep at you as well.

5.2.2 The Body of the insert-buffer Fun tion The body of the insert-buffer fun tion has two major parts: an or expression and a let expression. The purpose of the or expression is to ensure that the argument buffer is bound to a bu er and not just the name of a bu er. The body of the let expression ontains the ode whi h opies the other bu er into the urrent bu er. In outline, the two expressions t into the insert-buffer fun tion like this: (defun insert-buffer (buffer) "do umentation..." (intera tive "*bInsert buffer: ") (or ... ... (let (varlist) body-of-let... )

66

Chapter 5: A Few More Complex Fun tions

To understand how the or expression ensures that the argument buffer is bound to a bu er and not to the name of a bu er, it is rst ne essary to understand the or fun tion. Before doing this, let me rewrite this part of the fun tion using if so that you an see what is done in a manner that will be familiar.

5.2.3

insert-buffer

With an if Instead of an or

The job to be done is to make sure the value of buffer is a bu er itself and not the name of a bu er. If the value is the name, then the bu er itself must be got. You an imagine yourself at a onferen e where an usher is wandering around holding a list with your name on it and looking for you: the usher is \bound" to your name, not to you; but when the usher nds you and takes your arm, the usher be omes \bound" to you. In Lisp, you might des ribe this situation like this: (if (not (holding-on-to-guest)) (find-and-take-arm-of-guest))

We want to do the same thing with a bu er|if we do not have the bu er itself, we want to get it. Using a predi ate alled bufferp that tells us whether we have a bu er (rather than its name), we an write the ode like this: (if (not (bufferp buffer)) (setq buffer (get-buffer buffer)))

; if-part ; then-part

Here, the true-or-false-test of the if expression is (not (bufferp buffer)); and the then-part is the expression (setq buffer (get-buffer buffer)). In the test, the fun tion bufferp returns true if its argument is a bu er| but false if its argument is the name of the bu er. (The last hara ter of the fun tion name bufferp is the hara ter `p'; as we saw earlier, su h use of `p' is a onvention that indi ates that the fun tion is a predi ate, whi h is a term that means that the fun tion will determine whether some property is true or false. See Se tion 1.8.4, \Using the Wrong Type Obje t as an Argument", page 14.) The fun tion not pre edes the expression (bufferp buffer), so the trueor-false-test looks like this: (not (bufferp buffer))

not is a fun tion that returns true if its argument is false and false if its argument is true. So if (bufferp buffer) returns true, the not expression

returns false and vi e-versa: what is \not true" is false and what is \not false" is true. Using this test, the if expression works as follows: when the value of the variable buffer is a tually a bu er rather then its name, the true-orfalse-test returns false and the if expression does not evaluate the then-part.

The or in the Body

67

This is ne, sin e we do not need to do anything to the variable buffer if it really is a bu er. On the other hand, when the value of buffer is not a bu er itself, but the name of a bu er, the true-or-false-test returns true and the then-part of the expression is evaluated. In this ase, the then-part is (setq buffer (get-buffer buffer)). This expression uses the get-buffer fun tion to return an a tual bu er itself, given its name. The setq then sets the variable buffer to the value of the bu er itself, repla ing its previous value (whi h was the name of the bu er).

5.2.4 The or in the Body The purpose of the or expression in the insert-buffer fun tion is to ensure that the argument buffer is bound to a bu er and not just to the name of a bu er. The previous se tion shows how the job ould have been done using an if expression. However, the insert-buffer fun tion a tually uses or. To understand this, it is ne essary to understand how or works. An or fun tion an have any number of arguments. It evaluates ea h argument in turn and returns the value of the rst of its arguments that is not nil. Also, and this is a ru ial feature of or, it does not evaluate any subsequent arguments after returning the rst non-nil value. The or expression looks like this: (or (bufferp buffer) (setq buffer (get-buffer buffer)))

The rst argument to or is the expression (bufferp buffer). This expression returns true (a non-nil value) if the bu er is a tually a bu er, and not just the name of a bu er. In the or expression, if this is the ase, the or expression returns this true value and does not evaluate the next expression|and this is ne with us, sin e we do not want to do anything to the value of buffer if it really is a bu er. On the other hand, if the value of (bufferp buffer) is nil, whi h it will be if the value of buffer is the name of a bu er, the Lisp interpreter evaluates the next element of the or expression. This is the expression (setq buffer (get-buffer buffer)). This expression returns a non-nil value, whi h is the value to whi h it sets the variable buffer|and this value is a bu er itself, not the name of a bu er. The result of all this is that the symbol buffer is always bound to a bu er itself rather than to the name of a bu er. All this is ne essary be ause the set-buffer fun tion in a following line only works with a bu er itself, not with the name to a bu er.

68

Chapter 5: A Few More Complex Fun tions

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))

5.2.5 The let Expression in insert-buffer After ensuring that the variable buffer refers to a bu er itself and not just to the name of a bu er, the insert-buffer fun tion ontinues with a let expression. This spe i es three lo al variables, start, end, and newmark and binds them to the initial value nil. These variables are used inside the remainder of the let and temporarily hide any other o

urren e of variables of the same name in Ema s until the end of the let. The body of the let ontains two save-ex ursion expressions. First, we will look at the inner save-ex ursion expression in detail. The expression looks like this: (save-ex ursion (set-buffer buffer) (setq start (point-min) end (point-max)))

The expression (set-buffer buffer) hanges Ema s' attention from the

urrent bu er to the one from whi h the text will opied. In that bu er, the variables start and end are set to the beginning and end of the bu er, using the ommands point-min and point-max. Note that we have here an illustration of how setq is able to set two variables in the same expression. The rst argument of setq is set to the value of its se ond, and its third argument is set to the value of its fourth. After the body of the inner save-ex ursion is evaluated, the saveex ursion restores the original bu er, but start and end remain set to the values of the beginning and end of the bu er from whi h the text will be

opied. The outer save-ex ursion expression looks like this: (save-ex ursion (inner-save-ex ursion-expression (go-to-new-bu er-and-set-start-and-end) (insert-buffer-substring buffer start end) (setq newmark (point)))

The insert-buffer-substring fun tion opies the text into the urrent bu er from the region indi ated by start and end in buffer. Sin e the whole of the se ond bu er lies between start and end, the whole of the se ond bu er is opied into the bu er you are editing. Next, the value of point, whi h will be at the end of the inserted text, is re orded in the variable newmark. After the body of the outer save-ex ursion is evaluated, point and mark are relo ated to their original pla es.

Optional Arguments

69

However, it is onvenient to lo ate a mark at the end of the newly inserted text and lo ate point at its beginning. The newmark variable re ords the end of the inserted text. In the last line of the let expression, the (push-mark newmark) expression fun tion sets a mark to this lo ation. (The previous lo ation of the mark is still a

essible; it is re orded on the mark ring and you an go ba k to it with C-u C-hSPCi.) Meanwhile, point is lo ated at the beginning of the inserted text, whi h is where it was before you alled the insert fun tion. The whole let expression looks like this: (let (start end newmark) (save-ex ursion (save-ex ursion (set-buffer buffer) (setq start (point-min) end (point-max))) (insert-buffer-substring buffer start end) (setq newmark (point))) (push-mark newmark))

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.3 Complete De nition of beginning-of-buffer The basi stru ture of the beginning-of-buffer fun tion has already been dis ussed. (See Se tion 4.2, \A Simpli ed beginning-of-buffer Definition", page 52.) This se tion des ribes the omplex part of the de nition. As previously des ribed, when invoked without an argument, beginningof-buffer moves the ursor to the beginning of the bu er, leaving the mark

at the previous position. However, when the ommand is invoked with a number between one and ten, the fun tion onsiders that number to be a fra tion of the length of the bu er, measured in tenths, and Ema s moves the ursor that fra tion of the way from the beginning of the bu er. Thus, you an either all this fun tion with the key ommand M-<, whi h will move the ursor to the beginning of the bu er, or with a key ommand su h as C-u 7 M-< whi h will move the ursor to a point 70% of the way through the bu er. If a number bigger than ten is used for the argument, it moves to the end of the bu er. The beginning-of-buffer fun tion an be alled with or without an argument. The use of the argument is optional.

70

Chapter 5: A Few More Complex Fun tions

5.3.1 Optional Arguments Unless told otherwise, Lisp expe ts that a fun tion with an argument in its fun tion de nition will be alled with a value for that argument. If that does not happen, you get an error and a message that says `Wrong number of arguments'. However, optional arguments are a feature of Lisp: a keyword may be used to tell the Lisp interpreter that an argument is optional. The keyword is &optional. (The `&' in front of `optional' is part of the keyword.) In a fun tion de nition, if an argument follows the keyword &optional, a value does not need to be passed to that argument when the fun tion is alled. The rst line of the fun tion de nition of beginning-of-buffer therefore looks like this: (defun beginning-of-buffer (&optional arg)

In outline, the whole fun tion looks like this: (defun beginning-of-buffer (&optional arg) "do umentation..." (intera tive "P") (push-mark) (goto- har (if-there-is-an-argument

gure-out-where-to-go else-go-to (point-min))))

The fun tion is similar to the simplified-beginning-of-buffer fun tion ex ept that the intera tive expression has "P" as an argument and the goto- har fun tion is followed by an if-then-else expression that gures out where to put the ursor if there is an argument. The "P" in the intera tive expression tells Ema s to pass a pre x argument, if there is one, to the fun tion. A pre x argument is made by typing the hMETAi key followed by a number, or by typing C-u and then a number (if you don't type a number, C-u defaults to 4). The true-or-false-test of the if expression is simple: it is simply the argument arg. If arg has a value that is not nil, whi h will be the ase if beginning-of-buffer is alled with an argument, then this true-or-falsetest will return true and the then-part of the if expression will be evaluated. On the other hand, if beginning-of-buffer is not alled with an argument, the value of arg will be nil and the else-part of the if expression will be evaluated. The else-part is simply point-min, and when this is the out ome, the whole goto- har expression is (goto- har (point-min)), whi h is how we saw the beginning-of-buffer fun tion in its simpli ed form.

What happens in a large bu er

5.3.2

beginning-of-buffer

71

with an Argument

When beginning-of-buffer is alled with an argument, an expression is evaluated whi h al ulates what value to pass to goto- har. This expression is rather ompli ated at rst sight. It in ludes an inner if expression and mu h arithmeti . It looks like this: (if (> (buffer-size) 10000) ;; Avoid over ow for large bu er sizes! (* (prefix-numeri -value arg) (/ (buffer-size) 10)) (/ (+ 10 (* (buffer-size) (prefix-numeri -value arg))) 10))

Like other omplex-looking expressions, the onditional expression within

beginning-of-buffer an be disentangled by looking at it as parts of a

template, in this ase, the template for an if-then-else expression. In skeletal form, the expression looks like this: (if (bu er-is-large

divide-bu er-size-by-10-and-multiply-by-arg else-use-alternate- al ulation

The true-or-false-test of this inner if expression he ks the size of the bu er. The reason for this is that the old Version 18 Ema s used numbers that are no bigger than eight million or so and in the omputation that followed, the programmer feared that Ema s might try to use over-large numbers if the bu er were large. The term `over ow', mentioned in the

omment, means numbers that are over large. Version 21 Ema s uses larger numbers, but this ode has not been tou hed, if only be ause people now look at bu ers that are far, far larger than ever before. There are two ases: if the bu er is large and if it is not.

What happens in a large bu er In beginning-of-buffer, the inner if expression tests whether the size of the bu er is greater than 10,000 hara ters. To do this, it uses the > fun tion and the buffer-size fun tion. The line looks like this: (if (> (buffer-size) 10000)

When the bu er is large, the then-part of the if expression is evaluated. It reads like this (after formatting for easy reading): (* (prefix-numeri -value arg) (/ (buffer-size) 10))

This expression is a multipli ation, with two arguments to the fun tion *.

72

Chapter 5: A Few More Complex Fun tions

The rst argument is (prefix-numeri -value arg). When "P" is used as the argument for intera tive, the value passed to the fun tion as its argument is passed a \raw pre x argument", and not a number. (It is a number in a list.) To perform the arithmeti , a onversion is ne essary, and prefix-numeri -value does the job. The se ond argument is (/ (buffer-size) 10). This expression divides the numeri value of the bu er by ten. This produ es a number that tells how many hara ters make up one tenth of the bu er size. (In Lisp, / is used for division, just as * is used for multipli ation.) In the multipli ation expression as a whole, this amount is multiplied by the value of the pre x argument|the multipli ation looks like this: (* numeri -value-of-pre x-arg

number-of- hara ters-in-one-tenth-of-the-bu er )

If, for example, the pre x argument is `7', the one-tenth value will be multiplied by 7 to give a position 70% of the way through the bu er. The result of all this is that if the bu er is large, the goto- har expression reads like this: (goto- har (* (prefix-numeri -value arg) (/ (buffer-size) 10)))

This puts the ursor where we want it.

What happens in a small bu er If the bu er ontains fewer than 10,000 hara ters, a slightly di erent

omputation is performed. You might think this is not ne essary, sin e the rst omputation ould do the job. However, in a small bu er, the rst method may not put the ursor on exa tly the desired line; the se ond method does a better job. The ode looks like this: (/ (+ 10 (* (buffer-size) (prefix-numeri -value arg))) 10))

This is ode in whi h you gure out what happens by dis overing how the fun tions are embedded in parentheses. It is easier to read if you reformat it with ea h expression indented more deeply than its en losing expression: (/ (+ 10 (* (buffer-size) (prefix-numeri -value arg))) 10))

The Complete beginning-of-buffer

73

Looking at parentheses, we see that the innermost operation is (prefixnumeri -value arg), whi h onverts the raw argument to a number. This

number is multiplied by the bu er size in the following expression: (* (buffer-size) (prefix-numeri -value arg)

This multipli ation reates a number that may be larger than the size of the bu er|seven times larger if the argument is 7, for example. Ten is then added to this number and nally the large number is divided by ten to provide a value that is one hara ter larger than the per entage position in the bu er. The number that results from all this is passed to goto- har and the

ursor is moved to that point.

5.3.3 The Complete beginning-of-buffer Here is the omplete text of the beginning-of-buffer fun tion: (defun beginning-of-buffer (&optional arg) "Move point to the beginning of the buffer; leave mark at previous position. With arg N, put point N/10 of the way from the true beginning. Don't use this in Lisp programs! \(goto- har (point-min)) is faster and does not set the mark." (intera tive "P") (push-mark) (goto- har (if arg (if (> (buffer-size) 10000) ;; Avoid over ow for large bu er sizes! (* (prefix-numeri -value arg) (/ (buffer-size) 10)) (/ (+ 10 (* (buffer-size) (prefix-numeri -value arg))) 10)) (point-min))) (if arg (forward-line 1)))

Ex ept for two small points, the previous dis ussion shows how this fun tion works. The rst point deals with a detail in the do umentation string, and the se ond point on erns the last line of the fun tion. In the do umentation string, there is referen e to an expression: \(goto- har (point-min))

A `\' is used before the rst parenthesis of this expression. This `\' tells the Lisp interpreter that the expression should be printed as shown in the

74

Chapter 5: A Few More Complex Fun tions

do umentation rather than evaluated as a symboli expression, whi h is what it looks like. Finally, the last line of the beginning-of-buffer ommand says to move point to the beginning of the next line if the ommand is invoked with an argument: (if arg (forward-line 1)))

This puts the ursor at the beginning of the rst line after the appropriate tenths position in the bu er. This is a ourish that means that the ursor is always lo ated at least the requested tenths of the way through the bu er, whi h is a ni ety that is, perhaps, not ne essary, but whi h, if it did not o

ur, would be sure to draw omplaints.

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

5.5

optional

75

Argument Exer ise

Write an intera tive fun tion with an optional argument that tests whether its argument, a number, is greater or less than the value of fill olumn, and tells you whi h, in a message. However, if you do not pass an argument to the fun tion, use 56 as a default value.

76

Chapter 5: A Few More Complex Fun tions

The save-restri tion Spe ial Form

77

6 Narrowing and Widening Narrowing is a feature of Ema s that makes it possible for you to fo us on a spe i part of a bu er, and work without a

identally hanging other parts. Narrowing is normally disabled sin e it an onfuse novi es. With narrowing, the rest of a bu er is made invisible, as if it weren't there. This is an advantage if, for example, you want to repla e a word in one part of a bu er but not in another: you narrow to the part you want and the repla ement is arried out only in that se tion, not in the rest of the bu er. Sear hes will only work within a narrowed region, not outside of one, so if you are xing a part of a do ument, you an keep yourself from a

identally nding parts you do not need to x by narrowing just to the region you want. (The key binding for narrow-to-region is C-x n n.) However, narrowing does make the rest of the bu er invisible, whi h an s are people who inadvertently invoke narrowing and think they have deleted a part of their le. Moreover, the undo ommand (whi h is usually bound to C-x u) does not turn o narrowing (nor should it), so people an be ome quite desperate if they do not know that they an return the rest of a bu er to visibility with the widen ommand. (The key binding for widen is C-x n w.) Narrowing is just as useful to the Lisp interpreter as to a human. Often, an Ema s Lisp fun tion is designed to work on just part of a bu er; or

onversely, an Ema s Lisp fun tion needs to work on all of a bu er that has been narrowed. The what-line fun tion, for example, removes the narrowing from a bu er, if it has any narrowing and when it has nished its job, restores the narrowing to what it was. On the other hand, the ountlines fun tion, whi h is alled by what-line, uses narrowing to restri t itself to just that portion of the bu er in whi h it is interested and then restores the previous situation.

6.1 The save-restri tion Spe ial Form In Ema s Lisp, you an use the save-restri tion spe ial form to keep tra k of whatever narrowing is in e e t, if any. When the Lisp interpreter meets with save-restri tion, it exe utes the ode in the body of the saverestri tion expression, and then undoes any hanges to narrowing that the

ode aused. If, for example, the bu er is narrowed and the ode that follows save-restri tion gets rid of the narrowing, save-restri tion returns the bu er to its narrowed region afterwards. In the what-line ommand, any narrowing the bu er may have is undone by the widen ommand that immediately follows the save-restri tion ommand. Any original narrowing is restored just before the ompletion of the fun tion.

78

Chapter 6: Narrowing and Widening The template for a save-restri tion expression is simple: (save-restri tion body ... )

The body of the save-restri tion is one or more expressions that will be evaluated in sequen e by the Lisp interpreter. Finally, a point to note: when you use both save-ex ursion and saverestri tion, one right after the other, you should use save-ex ursion outermost. If you write them in reverse order, you may fail to re ord narrowing in the bu er to whi h Ema s swit hes after alling save-ex ursion. Thus, when written together, save-ex ursion and save-restri tion should be written like this: (save-ex ursion (save-restri tion body ...))

In other ir umstan es, when not written together, the save-ex ursion and save-restri tion spe ial forms must be written in the order appropriate to the fun tion. For example, (save-restri tion (widen) (save-ex ursion body ...))

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 effe 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 saverestri 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 ation 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.

6.3 Exer ise with Narrowing Write a fun tion that will display the rst 60 hara ters of the urrent bu er, even if you have narrowed the bu er to its latter half so that the rst line is ina

essible. Restore point, mark, and narrowing. For this exer ise, you need to use save-restri tion, widen, goto- har, point-min, buffersubstring, message, and other fun tions, a whole potpourri.

80

Chapter 6: Narrowing and Widening

ar and dr

7

ar, dr, ons:

81

Fundamental Fun tions

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 evaluating 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 You an see this by evaluating the following in the usual way: ( dr '(rose violet daisy butter up))

When you evaluate this, (violet daisy butter up) will appear in the e ho area. Like ar, dr does not remove any elements from the list|it just returns a report of what the se ond and subsequent elements are. In identally, in the example, the list of owers is quoted. If it were not, the Lisp interpreter would try to evaluate the list by alling rose as a fun tion. In this example, we do not want to do that. Clearly, a more reasonable name for dr would be rest. (There is a lesson here: when you name new fun tions, onsider very

arefully what you are doing, sin e you may be stu k with the names for far longer than you expe t. The reason this do ument perpetuates these names is that the Ema s Lisp sour e ode uses them, and if I did not use them, you would have a hard time reading the ode; but do, please, try to avoid using these terms yourself. The people who ome after you will be grateful to you.) When ar and dr are applied to a list made up of symbols, su h as the list (pine fir oak maple), the element of the list returned by the fun tion

ar is the symbol pine without any parentheses around it. pine is the rst element in the list. However, the dr of the list is a list itself, (fir oak maple), as you an see by evaluating the following expressions in the usual way: ( ar '(pine fir oak maple)) ( dr '(pine fir oak maple))

On the other hand, in a list of lists, the rst element is itself a list. ar returns this rst element as a list. For example, the following list ontains three sub-lists, a list of arnivores, a list of herbivores and a list of sea mammals: ( ar '((lion tiger heetah) (gazelle antelope zebra) (whale dolphin seal)))

In this example, the rst element or ar of the list is the list of arnivores, (lion tiger heetah), and the rest of the list is ((gazelle antelope zebra) (whale dolphin seal)). ( dr '((lion tiger heetah) (gazelle antelope zebra) (whale dolphin seal)))

It is worth saying again that ar and dr are non-destru tive|that is, they do not modify or hange lists to whi h they are applied. This is very important for how they are used.

83

ons

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

be ause there is nothing in an empty list. Generally speaking, an empty list is invisible. The se ond example, ( ons 'daisy '(butter up)) onstru ts a new, two element list by putting daisy in front of butter up; and the third example onstru ts a three element list by putting violet in front of daisy and butter up.

7.2.1 Find the Length of a List:

length

You an nd out how many elements there are in a list by using the Lisp fun tion length, as in the following examples: (length '(butter up)) ) 1 (length '(daisy butter up)) ) 2 (length ( ons 'violet '(daisy butter up))) ) 3

In the third example, the ons fun tion is used to onstru t a three element list whi h is then passed to the length fun tion as its argument. We an also use length to ount the number of elements in an empty list: (length ()) ) 0

As you would expe t, the number of elements in an empty list is zero. An interesting experiment is to nd out what happens if you try to nd the length of no list at all; that is, if you try to all length without giving it an argument, not even an empty list: (length )

What you see, if you evaluate this, is the error message Wrong number of arguments: #<subr length>, 0

This means that the fun tion re eives the wrong number of arguments, zero, when it expe ts some other number of arguments. In this ase, one argument is expe ted, the argument being a list whose length the fun tion is measuring. (Note that one list is one argument, even if the list has many elements inside it.) The part of the error message that says `#<subr length>' is the name of the fun tion. This is written with a spe ial notation, `#<subr', that indi ates that the fun tion length is one of the primitive fun tions written in C rather than in Ema s Lisp. (`subr' is an abbreviation for `subroutine'.) See se tion \What Is a Fun tion?" in The GNU Ema s Lisp Referen e Manual, for more about subroutines.

nth dr

7.3

85

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. be:

Thus, if it were not de ned in C for speed, the de nition of nth would (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" (nth 1 '("one" "two" "three")) ) "two"

It is worth mentioning that nth, like nth dr and dr, does not hange the original list|the fun tion is non-destru tive. This is in sharp ontrast to the set ar and set dr fun tions.

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 interested 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).

7.7 Exer ise Constru t a list of four birds by evaluating several expressions with ons. Find out what happens when you ons a list onto itself. Repla e the rst element of the list of four birds with a sh. Repla e the rest of that list with a list of other sh.

zap-to- har

89

8 Cutting and Storing Text Whenever you ut or lip text out of a bu er with a `kill' ommand in GNU Ema s, it is stored in a list and you an bring it ba k with a `yank'

ommand. (The use of the word `kill' in Ema s for pro esses whi h spe i ally do not destroy the values of the entities is an unfortunate histori al a

ident. A mu h more appropriate word would be ` lip' sin e that is what the kill

ommands do; they lip text out of a bu er and put it into storage from whi h it an be brought ba k. I have often been tempted to repla e globally all o

urren es of `kill' in the Ema s sour es with ` lip' and all o

urren es of `killed' with ` lipped'.) When text is ut out of a bu er, it is stored on a list. Su

essive pie es of text are stored on the list su

essively, so the list might look like this: ("a pie e of text" "previous pie e")

The fun tion ons an be used to add a pie e of text to the list, like this: ( ons "another pie e" '("a pie e of text" "previous pie e"))

If you evaluate this expression, a list of three elements will appear in the e ho area: ("another pie e" "a pie e of text" "previous pie e")

With the ar and nth dr fun tions, you an retrieve whi hever pie e of text you want. For example, in the following ode, nth dr 1 ... returns the list with the rst item removed; and the ar returns the rst element of that remainder|the se ond element of the original list: ( ar (nth dr 1 '("another pie e" "a pie e of text" "previous pie e"))) ) "a pie e of text"

The a tual fun tions in Ema s are more omplex than this, of ourse. The ode for utting and retrieving text has to be written so that Ema s

an gure out whi h element in the list you want|the rst, se ond, third, or whatever. In addition, when you get to the end of the list, Ema s should give you the rst element of the list, rather than nothing at all. The list that holds the pie es of text is alled the kill ring. This hapter leads up to a des ription of the kill ring and how it is used by rst tra ing how the zap-to- har fun tion works. This fun tion uses (or ` alls') a fun tion that invokes a fun tion that manipulates the kill ring. Thus, before rea hing the mountains, we limb the foothills. A subsequent hapter des ribes how text that is ut from the bu er is retrieved. See Chapter 10, \Yanking Text Ba k", page 117.

90

Chapter 8: Cutting and Storing Text

8.1

zap-to- har

The zap-to- har fun tion barely hanged between GNU Ema s version 19 and GNU Ema s version 21. However, zap-to- har alls another fun tion, kill-region, whi h enjoyed a major rewrite on the way to version 21. The kill-region fun tion in Ema s 19 is omplex, but does not use ode that is important at this time. We will skip it. The kill-region fun tion in Ema s 21 is easier to read than the same fun tion in Ema s 19 and introdu es a very important on ept, that of error handling. We will walk through the fun tion. But rst, let us look at the intera tive zap-to- har fun tion. The GNU Ema s version 19 and version 21 implementations of the zapto- har fun tion are nearly identi al in form, and they work alike. The fun tion removes the text in the region between the lo ation of the ursor (i.e., of point) up to and in luding the next o

urren e of a spe i ed hara ter. The text that zap-to- har removes is put in the kill ring; and it an be retrieved from the kill ring by typing C-y (yank). If the ommand is given an argument, it removes text through that number of o

urren es. Thus, if the ursor were at the beginning of this senten e and the hara ter were `s', `Thus' would be removed. If the argument were two, `Thus, if the urs' would be removed, up to and in luding the `s' in ` ursor'. If the spe i ed hara ter is not found, zap-to- har will say \Sear h failed", tell you the hara ter you typed, and not remove any text. In order to determine how mu h text to remove, zap-to- har uses a sear h fun tion. Sear hes are used extensively in ode that manipulates text, and we will fo us attention on them as well as on the deletion ommand. Here is the omplete text of the version 19 implementation of the fun tion: (defun zap-to- har (arg har) ; version 19 implementation "Kill up to and in luding ARG'th o

urren e of CHAR. Goes ba kward if ARG is negative; error if CHAR not found." (intera tive "*p\n Zap to har: ") (kill-region (point) (progn (sear h-forward ( har-to-string har) nil nil arg) (point))))

8.1.1 The intera tive Expression The intera tive expression in the zap-to- har ommand looks like this: (intera tive "*p\n Zap to har: ")

The part within quotation marks, "*p\n Zap to har: ", spe i es three di erent things. First, and most simply, the asterisk, `*', auses an error to

The sear h-forward Fun tion

91

be signalled if the bu er is read-only. This means that if you try zap-to har in a read-only bu er you will not be able to remove text, and you will

re eive a message that says \Bu er is read-only"; your terminal may beep at you as well. The version 21 implementation does not have the asterisk, `*'. The fun tion works the same as in version 19: in both ases, it annot remove text from a read-only bu er but the fun tion does opy the text that would have been removed to the kill ring. Also, in both ases, you see an error message. However, the version 19 implementation opies text from a read-only bu er only be ause of a mistake in the implementation of intera tive. A

ording to the do umentation for intera tive, the asterisk, `*', should prevent the zap-to- har fun tion from doing anything at all when the bu er is read only. The fun tion should not opy the text to the kill ring. It is a bug that it does. In version 21, intera tive is implemented orre tly. So the asterisk, `*', had to be removed from the intera tive spe i ation. If you insert an `*' and evaluate the fun tion de nition, then the next time you run the zap-to- har fun tion on a read-only bu er, you will not opy any text. That hange aside, and a hange to the do umentation, the two versions of the zap-to- har fun tion are identi al. Let us ontinue with the intera tive spe i ation. The se ond part of "*p\n Zap to har: " is the `p'. This part is separated from the next part by a newline, `\n'. The `p' means that the rst argument to the fun tion will be passed the value of a `pro essed pre x'. The pre x argument is passed by typing C-u and a number, or M- and a number. If the fun tion is alled intera tively without a pre x, 1 is passed to this argument. The third part of "*p\n Zap to har: " is ` Zap to har: '. In this part, the lower ase ` ' indi ates that intera tive expe ts a prompt and that the argument will be a hara ter. The prompt follows the ` ' and is the string `Zap to har: ' (with a spa e after the olon to make it look good). What all this does is prepare the arguments to zap-to- har so they are of the right type, and give the user a prompt.

8.1.2 The Body of zap-to- har The body of the zap-to- har fun tion ontains the ode that kills (that is, removes) the text in the region from the urrent position of the ursor up to and in luding the spe i ed hara ter. The rst part of the ode looks like this: (kill-region (point) ...

(point) is the urrent position of the ursor.

The next part of the ode is an expression using progn. The body of the progn onsists of alls to sear h-forward and point.

92

Chapter 8: Cutting and Storing Text

It is easier to understand how progn works after learning about sear hforward, so we will look at sear h-forward and then at progn.

8.1.3 The sear h-forward Fun tion The sear h-forward fun tion is used to lo ate the zapped-for- hara ter in zap-to- har. If the sear h is su

essful, sear h-forward leaves point immediately after the last hara ter in the target string. (In zap-to- har, the target string is just one hara ter long.) If the sear h is ba kwards, sear h-forward leaves point just before the rst hara ter in the target. Also, sear h-forward returns t for true. (Moving point is therefore a `side e e t'.) In zap-to- har, the sear h-forward fun tion looks like this: (sear h-forward ( har-to-string har) nil nil arg)

The sear h-forward fun tion takes four arguments: 1. The rst argument is the target, what is sear hed for. This must be a string, su h as `"z"'. As it happens, the argument passed to zap-to- har is a single hara ter. Be ause of the way omputers are built, the Lisp interpreter may treat a single hara ter as being di erent from a string of hara ters. Inside the omputer, a single hara ter has a di erent ele troni format than a string of one hara ter. (A single hara ter an often be re orded in the omputer using exa tly one byte; but a string may be longer, and the omputer needs to be ready for this.) Sin e the sear h-forward fun tion sear hes for a string, the hara ter that the zap-to- har fun tion re eives as its argument must be onverted inside the omputer from one format to the other; otherwise the sear h-forward fun tion will fail. The har-to-string fun tion is used to make this onversion. 2. The se ond argument bounds the sear h; it is spe i ed as a position in the bu er. In this ase, the sear h an go to the end of the bu er, so no bound is set and the se ond argument is nil. 3. The third argument tells the fun tion what it should do if the sear h fails|it an signal an error (and print a message) or it an return nil. A nil as the third argument auses the fun tion to signal an error when the sear h fails. 4. The fourth argument to sear h-forward is the repeat ount|how many o

urren es of the string to look for. This argument is optional and if the fun tion is alled without a repeat ount, this argument is passed the value 1. If this argument is negative, the sear h goes ba kwards.

Summing up zap-to- har

93

In template form, a sear h-forward expression looks like this: (sear h-forward "target-string "

limit-of-sear h what-to-do-if-sear h-fails repeat- ount)

We will look at progn next.

8.1.4 The progn Spe ial Form progn is a spe ial form that auses ea h of its arguments to be evaluated in sequen e and then returns the value of the last one. The pre eding expressions are evaluated only for the side e e ts they perform. The values produ ed by them are dis arded. The template for a progn expression is very simple: (progn

body ...)

In zap-to- har, the progn expression has to do two things: put point in exa tly the right position; and return the lo ation of point so that killregion will know how far to kill to. The rst argument to the progn is sear h-forward. When sear hforward nds the string, the fun tion leaves point immediately after the last hara ter in the target string. (In this ase the target string is just one

hara ter long.) If the sear h is ba kwards, sear h-forward leaves point just before the rst hara ter in the target. The movement of point is a side e e t. The se ond and last argument to progn is the expression (point). This expression returns the value of point, whi h in this ase will be the lo ation to whi h it has been moved by sear h-forward. This value is returned by the progn expression and is passed to kill-region as kill-region's se ond argument.

8.1.5 Summing up zap-to- har Now that we have seen how sear h-forward and progn work, we an see how the zap-to- har fun tion works as a whole. The rst argument to kill-region is the position of the ursor when the zap-to- har ommand is given|the value of point at that time. Within the progn, the sear h fun tion then moves point to just after the zappedto- hara ter and point returns the value of this lo ation. The kill-region fun tion puts together these two values of point, the rst one as the beginning of the region and the se ond one as the end of the region, and removes the region. The progn spe ial form is ne essary be ause the kill-region ommand takes two arguments; and it would fail if sear h-forward and point ex-

94

Chapter 8: Cutting and Storing Text

pressions were written in sequen e as two additional arguments. The progn expression is a single argument to kill-region and returns the one value that kill-region needs for its se ond argument.

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 opyregion-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

;; `kill-append' on atenates the new string and the old. ;; `kill-new' inserts text into a new item in the kill ring. (when string (if (eq last- ommand 'kill-region) ;; if true, prepend string (kill-append string (< end beg)) (kill-new string))) (setq this- ommand 'kill-region)) ;; 3. The third argument to ` ondition- ase' tells the interpreter ;; what to do with an error. ;; The third argument has a onditions part and a body part. ;; If the onditions are met (in this ase, ;; if text or buffer is read-only) ;; then the body is exe uted. ((buffer-read-only text-read-only) ;; this is the if-part ;; then... ( opy-region-as-kill beg end) (if kill-read-only-ok ;; usually this variable is nil (message "Read only text opied to kill ring") ;; or else, signal an error if the buffer is read-only; (barf-if-buffer-read-only) ;; and, in any ase, signal that the text is read-only. (signal 'text-read-only (list ( urrent-buffer)))))))

8.2.1

ondition- ase

As we have seen earlier (see Se tion 1.3, \Generate an Error Message", page 4), when the Ema s Lisp interpreter has trouble evaluating an expression, it provides you with help; in the jargon, this is alled \signaling an error". Usually, the omputer stops the program and shows you a message. However, some programs undertake ompli ated a tions. They should not simply stop on an error. In the kill-region fun tion, the most likely error is that you will try to kill text that is read-only and annot be removed. So the kill-region fun tion ontains ode to handle this ir umstan e. This

ode, whi h makes up the body of the kill-region fun tion, is inside of a

ondition- ase spe ial form. The template for ondition- ase looks like this: ( ondition- ase

var bodyform error-handler ...)

The se ond argument, bodyform, is straightforward. The ondition ase spe ial form auses the Lisp interpreter to evaluate the ode in body-

96

Chapter 8: Cutting and Storing Text

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 generating 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.

8.2.2

delete-and-extra t-region

A ondition- ase expression has two parts, a part that is evaluated in the expe tation that all will go well, but whi h may generate an error; and a part that is evaluated when there is an error. First, let us look at the ode in kill-region that is run in the expe tation that all goes well. This is the ore of the fun tion. The ode looks like this: (let ((string (delete-and-extra t-region beg end))) (when string (if (eq last- ommand 'kill-region) (kill-append string (< end beg)) (kill-new string))) (setq this- ommand 'kill-region))

It looks ompli ated be ause we have the new fun tions delete-andextra t-region, kill-append, and kill-new as well as the new variables, last- ommand and this- ommand. The delete-and-extra t-region fun tion is straightforward. It is a built-in fun tion that deletes the text in a region (a side e e t) and also returns that text. This is the fun tion that a tually removes the text. (And if it annot do that, it signals the error.)

delete-and-extra t-region: Digressing into C

97

In this let expression, the text that delete-and-extra t-region returns is pla ed in the lo al variable alled `string'. This is the text that is removed from the bu er. (To be more pre ise, the variable is set to point to the address of the extra ted text; to say it is `pla ed in' the variable is simply a shorthand.) If the variable `string' does point to text, that text is added to the kill ring. The variable will have a nil value if no text was removed. The ode uses when to determine whether the variable `string' points to text. A when statement is simply a programmers' onvenien e. A when statement is an if statement without the possibility of an else lause. In your mind, you an repla e when with if and understand what goes on. That is what the Lisp interpreter does. Te hni ally speaking, when is a Lisp ma ro. A Lisp ma ro enables you to de ne new ontrol onstru ts and other language features. It tells the interpreter how to ompute another Lisp expression whi h will in turn ompute the value. In this ase, the `other expression' is an if expression. For more about Lisp ma ros, see se tion \Ma ros" in The GNU Ema s Lisp Referen e Manual. The C programming language also provides ma ros. These are di erent, but also useful. We will brie y look at C ma ros in Se tion 8.3, \delete-and-extra t-region: Digressing into C", page 98. If the string has ontent, then another onditional expression is exe uted. This is an if with both a then-part and an else-part. (if (eq last- ommand 'kill-region) (kill-append string (< end beg)) (kill-new string)))

The then-part is evaluated if the previous ommand was another all to

kill-region; if not, the else-part is evaluated.

last- ommand is a variable that omes with Ema s that we have not seen before. Normally, whenever a fun tion is exe uted, Ema s sets the value of last- ommand to the previous ommand. In this segment of the de nition, the if expression he ks whether the previous ommand was kill-region. If it was, (kill-append string (< end beg))

on atenates a opy of the newly lipped text to the just previously lipped text in the kill ring. (If the (< end beg)) expression is true, kill-append prepends the string to the just previously lipped text. For a detailed dis ussion, see \The kill-append fun tion", page 104.) If you then yank ba k the text, i.e., `paste' it, you get both pie es of text at on e. That way, if you delete two words in a row, and then yank them ba k, you get both words, in their proper order, with one yank. (The (< end beg)) expression makes sure the order is orre t.)

98

Chapter 8: Cutting and Storing Text

On the other hand, if the previous ommand is not kill-region, then the kill-new fun tion is alled, whi h adds the text to the kill ring as the latest item, and sets the kill-ring-yank-pointer variable to point to it.

8.3

delete-and-extra t-region:

Digressing into C

The zap-to- har ommand uses the delete-and-extra t-region fun tion, whi h in turn uses two other fun tions, opy-region-as-kill and del_range_1. The opy-region-as-kill fun tion will be des ribed in a following se tion; it puts a opy of the region in the kill ring so it an be yanked ba k. (See Se tion 8.5, \ opy-region-as-kill", page 102.) The delete-and-extra t-region fun tion removes the ontents of a region and you annot get them ba k. Unlike the other ode dis ussed here, delete-and-extra t-region is not written in Ema s Lisp; it is written in C and is one of the primitives of the GNU Ema s system. Sin e it is very simple, I will digress brie y from Lisp and des ribe it here. Like many of the other Ema s primitives, delete-and-extra t-region is written as an instan e of a C ma ro, a ma ro being a template for ode. The omplete ma ro looks like this: DEFUN ("delete-and-extra t-region", Fdelete_and_extra t_region, Sdelete_and_extra t_region, 2, 2, 0, "Delete the text between START and END and return it.") (start, end) Lisp_Obje t start, end; { validate_region (&start, &end); return del_range_1 (XINT (start), XINT (end), 1, 1); }

Without going into the details of the ma ro writing pro ess, let me point out that this ma ro starts with the word DEFUN. The word DEFUN was hosen sin e the ode serves the same purpose as defun does in Lisp. The word DEFUN is followed by seven parts inside of parentheses:  The rst part is the name given to the fun tion in Lisp, delete-andextra t-region.  The se ond part is the name of the fun tion in C, Fdelete_and_ extra t_region. By onvention, it starts with `F'. Sin e C does not use hyphens in names, unders ores are used instead.  The third part is the name for the C onstant stru ture that re ords information on this fun tion for internal use. It is the name of the fun tion in C but begins with an `S' instead of an `F'.  The fourth and fth parts spe ify the minimum and maximum number of arguments the fun tion an have. This fun tion demands exa tly 2 arguments.

delete-and-extra t-region: Digressing into C





99

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 quotation 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).

In a C ma ro, the formal parameters ome next, with a statement of what kind of obje t they are, followed by what might be alled the `body' of the ma ro. For delete-and-extra t-region the `body' onsists of the following two lines: validate_region (&start, &end); return del_range_1 (XINT (start), XINT (end), 1, 1);

The rst fun tion, validate_region he ks whether the values passed as the beginning and end of the region are the proper type and are within range. The se ond fun tion, del_range_1, a tually deletes the text. del_range_1 is a omplex fun tion we will not look into. It updates the bu er and does other things. However, it is worth looking at the two arguments passed to del_range. These are XINT (start) and XINT (end). As far as the C language is on erned, start and end are two integers that mark the beginning and end of the region to be deleted1 . In early versions of Ema s, these two numbers were thirty-two bits long, but the ode is slowly being generalized to handle other lengths. Three of the available bits are used to spe ify the type of information and a fourth bit is used for handling the omputer's memory; the remaining bits are used as ` ontent'. `XINT' is a C ma ro that extra ts the relevant number from the longer

olle tion of bits; the four other bits are dis arded. 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

The ommand in delete-and-extra t-region looks like this: del_range_1 (XINT (start), XINT (end), 1, 1);

It deletes the region between the beginning position, start, and the ending position, end. From the point of view of the person writing Lisp, Ema s is all very simple; but hidden underneath is a great deal of omplexity to make it all work.

8.4 Initializing a Variable with defvar Unlike the delete-and-extra t-region fun tion, the opy-region-askill fun tion is written in Ema s Lisp. Two fun tions within it, killappend and kill-new, opy a region in a bu er and save it in a variable

alled the kill-ring. This se tion des ribes how the kill-ring variable is

reated and initialized using the defvar spe ial form. (Again we note that the term kill-ring is a misnomer. The text that is lipped out of the bu er an be brought ba k; it is not a ring of orpses, but a ring of resurre table text.) In Ema s Lisp, a variable su h as the kill-ring is reated and given an initial value by using the defvar spe ial form. The name omes from \de ne variable". The defvar spe ial form is similar to setq in that it sets the value of a variable. It is unlike setq in two ways: rst, it only sets the value of the variable if the variable does not already have a value. If the variable already has a value, defvar does not override the existing value. Se ond, defvar has a do umentation string. (Another spe ial form, def ustom, is designed for variables that people

ustomize. It has more features than defvar. (See Se tion 16.2, \Setting Variables with def ustom", page 214.) You an see the urrent value of a variable, any variable, by using the des ribe-variable fun tion, whi h is usually invoked by typing C-h v. If you type C-h v and then kill-ring (followed by hRETi) when prompted, you will see what is in your urrent kill ring|this may be quite a lot! Conversely, if you have been doing nothing this Ema s session ex ept read this do ument, you may have nothing in it. Also, you will see the do umentation for killring: Do umentation: List of killed text sequen es. Sin e the kill ring is supposed to intera t ni ely with ut-and-paste fa ilities offered by window systems, use of this variable should

opy-region-as-kill

101

intera t ni ely with `interprogram- ut-fun tion' and `interprogram-paste-fun tion'. The fun tions `kill-new', `kill-append', and ` urrent-kill' are supposed to implement this intera tion; you may want to use them instead of manipulating the kill ring dire tly.

The kill ring is de ned by a defvar in the following way: (defvar kill-ring nil "List of killed text sequen es. ...")

In this variable de nition, the variable is given an initial value of nil, whi h makes sense, sin e if you have saved nothing, you want nothing ba k if you give a yank ommand. The do umentation string is written just like the do umentation string of a defun. As with the do umentation string of the defun, the rst line of the do umentation should be a omplete senten e, sin e some ommands, like apropos, print only the rst line of do umentation. Su

eeding lines should not be indented; otherwise they look odd when you use C-h v (des ribe-variable).

8.4.1

defvar

and an asterisk

In the past, Ema s used the defvar spe ial form both for internal variables that you would not expe t a user to hange and for variables that you do expe t a user to hange. Although you an still use defvar for user ustomizable variables, please use def ustom instead, sin e that spe ial form provides a path into the Customization ommands. (See Se tion 16.2, \Setting Variables with def ustom", page 214.) When you spe i ed a variable using the defvar spe ial form, you ould distinguish a readily settable variable from others by typing an asterisk, `*', in the rst olumn of its do umentation string. For example: (defvar shell- ommand-default-error-buffer nil "*Buffer name for `shell- ommand' ... error output. ... ")

This means that you ould (and still an) use the edit-options ommand to hange the value of shell- ommand-default-error-buffer temporarily. However, options set using edit-options are set only for the duration of your editing session. The new values are not saved between sessions. Ea h time Ema s starts, it reads the original value, unless you hange the value within your `.ema s' le, either by setting it manually or by using

ustomize. See Chapter 16, \Your `.ema s' File", page 213. For me, the major use of the edit-options ommand is to suggest variables that I might want to set in my `.ema s' le. I urge you to look through the list. (See se tion \Editing Variable Values" in The GNU Ema s Manual.)

102

8.5

Chapter 8: Cutting and Storing Text

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 ommand, 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, understanding 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 sidee 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 erent 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 situations: whether or not this ommand is exe uted immediately after a previous 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.

8.5.1 The Body of opy-region-as-kill The opy-region-as-kill fun tion works in mu h the same way as the kill-region fun tion (see Se tion 8.2, \kill-region", page 94). Both are

written so that two or more kills in a row ombine their text into a single entry. If you yank ba k the text from the kill ring, you get it all in one pie e. Moreover, kills that kill forward from the urrent position of the ursor are added to the end of the previously opied text and ommands that opy text ba kwards add it to the beginning of the previously opied text. This way, the words in the text stay in the proper order. Like kill-region, the opy-region-as-kill fun tion makes use of the last- ommand variable that keeps tra k of the previous Ema s ommand. Normally, whenever a fun tion is exe uted, Ema s sets the value of this ommand to the fun tion being exe uted (whi h in this ase would be opyregion-as-kill). At the same time, Ema s sets the value of last- ommand to the previous value of this- ommand. In the rst part of the body of the opy-region-as-kill fun tion, an if expression determines whether the value of last- ommand is kill-region. If so, the then-part of the if expression is evaluated; it uses the kill-append fun tion to on atenate the text opied at this all to the fun tion with the text already in the rst element (the ar) of the kill ring. On the other hand, if the value of last- ommand is not kill-region, then the opyregion-as-kill fun tion atta hes a new element to the kill ring using the kill-new fun tion.

104

Chapter 8: Cutting and Storing Text

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 interpreter alls the kill-append fun tion

The kill-append fun tion The kill-append fun tion looks like this: (defun kill-append (string before-p) "Append STRING to the end of the latest kill in the kill ring. If BEFORE-P is non-nil, prepend STRING to the kill. If `interprogram- ut-fun tion' is set, pass the resulting kill to it." (kill-new (if before-p ( on at string ( ar kill-ring)) ( on at ( ar kill-ring) string)) t))

The kill-append fun tion is fairly straightforward. It uses the kill-new fun tion, whi h we will dis uss in more detail in a moment. First, let us look at the onditional that is one of the two arguments to kill-new. It uses on at to on atenate the new text to the ar of the kill ring. Whether it prepends or appends the text depends on the results of an if expression: (if before-p ( on at string ( ar kill-ring)) ( on at ( ar kill-ring) string))

; if-part ; then-part ; else-part

If the region being killed is before the region that was killed in the last

ommand, then it should be prepended before the material that was saved in the previous kill; and onversely, if the killed text follows what was just killed, it should be appended after the previous text. The if expression depends on the predi ate before-p to de ide whether the newly saved text should be put before or after the previously saved text.

The kill-new fun tion

105

The symbol before-p is the name of one of the arguments to killappend. When the kill-append fun tion is evaluated, it is bound to the

value returned by evaluating the a tual argument. In this ase, this is the expression (< end beg). This expression does not dire tly determine whether the killed text in this ommand is lo ated before or after the kill text of the last ommand; what is does is determine whether the value of the variable end is less than the value of the variable beg. If it is, it means that the user is most likely heading towards the beginning of the bu er. Also, the result of evaluating the predi ate expression, (< end beg), will be true and the text will be prepended before the previous text. On the other hand, if the value of the variable end is greater than the value of the variable beg, the text will be appended after the previous text. When the newly saved text will be prepended, then the string with the new text will be on atenated before the old text: ( on at string ( ar kill-ring))

But if the text will be appended, it will be on atenated after the old text: ( on at ( ar kill-ring) string))

To understand how this works, we rst need to review the on at fun tion. The on at fun tion links together or unites two strings of text. The result is a string. For example: ( on at "ab " "def") ) "ab def" ( on at "new " ( ar '("first element" "se ond element"))) ) "new first element" ( 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.

The kill-new fun tion The kill-new fun tion looks like this: (defun kill-new (string &optional repla e) "Make STRING the latest kill in the kill ring. Set the kill-ring-yank pointer to point to it. If `interprogram- ut-fun tion' is non-nil, apply it to STRING. Optional se ond argument REPLACE non-nil means that STRING will repla e the front of the kill ring, rather than being added to the list."

106

Chapter 8: Cutting and Storing Text (and (fboundp 'menu-bar-update-yank-menu) (menu-bar-update-yank-menu string (and repla e ( ar kill-ring)))) (if (and repla e kill-ring) (set ar kill-ring string) (setq kill-ring ( ons string kill-ring)) (if (> (length kill-ring) kill-ring-max) (set dr (nth dr (1- kill-ring-max) kill-ring) nil))) (setq kill-ring-yank-pointer kill-ring) (if interprogram- ut-fun tion (fun all interprogram- ut-fun tion string (not repla e))))

As usual, we an look at this fun tion in parts. The rst line of the do umentation makes sense: Make STRING the latest kill in the kill ring.

Let's skip over the rest of the do umentation for the moment. Also, let's skip over the rst two lines of ode, those involving menu-barupdate-yank-menu. We will explain them below. The riti al lines are these: (if (and repla e kill-ring) ;; then (set ar kill-ring string) ;; else (setq kill-ring ( ons string kill-ring)) (if (> (length kill-ring) kill-ring-max) ;; avoid overly long kill ring (set dr (nth dr (1- kill-ring-max) kill-ring) nil))) (setq kill-ring-yank-pointer kill-ring) (if interprogram- ut-fun tion (fun all interprogram- ut-fun tion string (not repla e))))

The onditional test is (and repla e kill-ring). This will be true when two onditions are met: the kill ring has something in it, and the repla e variable is true. The kill-append fun tion sets repla e to be true; then, when the kill ring has at least one item in it, the set ar expression is exe uted: (set ar kill-ring string)

The set ar fun tion a tually hanges the rst element of the kill-ring list to the value of string. It repla es the rst element. On the other hand, if the kill ring is empty, or repla e is false, the else-part of the ondition is exe uted: (setq kill-ring ( ons string kill-ring)) (if (> (length kill-ring) kill-ring-max) (set dr (nth dr (1- kill-ring-max) kill-ring) nil))

The kill-new fun tion

107

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 examplelist 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-updateyank-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

message, as we did when we reated errors intentionally (see Se tion 1.3, \Generate an Error Message", page 4). Essentially, the and is an if expression that reads like this: if the-menu-bar-fun tion-exists then exe ute-it

menu-bar-update-yank-menu is one of the fun tions that make it possible to use the `Sele t and Paste' menu in the Edit item of a menu bar; using a mouse, you an look at the various pie es of text you have saved and sele t one pie e to paste. Finally, the last expression in the kill-new fun tion adds the newly

opied string to whatever fa ility exists for opying and pasting among different programs running in a windowing system. In the X Windowing system, for example, the x-sele t-text fun tion takes the string and stores it in memory operated by X. You an paste the string in another program, su h as an Xterm. The expression looks like this: (if interprogram- ut-fun tion (fun all interprogram- ut-fun tion string (not repla e))))

If an interprogram- ut-fun tion exists, then Ema s exe utes fun all, whi h in turn alls its rst argument as a fun tion and passes the remaining arguments to it. (In identally, as far as I an see, this if expression ould be repla ed by an and expression similar to the one in the rst part of the fun tion.) We are not going to dis uss windowing systems and other programs further, but merely note that this is a me hanism that enables GNU Ema s to work easily and well with other programs. This ode for pla ing text in the kill ring, either on atenated with an existing element or as a new element, leads us to the ode for bringing ba k text that has been ut out of the bu er|the yank ommands. However, before dis ussing the yank ommands, it is better to learn how lists are implemented in a omputer. This will make lear su h mysteries as the use of the term `pointer'.

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)

ons

ons onstru ts a list by prepending its rst argument to its se ond argument. For example: ( ons 1 '(2 3 4)) ) (1 2 3 4)

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)) (set ar triple '37) triple ) (37 2 3) (set dr triple '("foo" "bar")) triple ) (37 "foo" "bar")

progn

Evaluate ea h argument in sequen e and then return the value of the last. For example: (progn 1 2 3 4) ) 4

save-restri tion

Re ord whatever narrowing is in e e t in the urrent bu er, if any, and restore that narrowing after evaluating the arguments.

sear h-forward

Sear h for a string, and if the string is found, move point.

Sear hing Exer ises

111

Takes four arguments: 1. The string 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 negative, the sear h goes ba kwards. kill-region delete-region

opy-region-as-kill kill-region uts the text between point and mark from the

bu er and stores that text in the kill ring, so you an get it ba k by yanking. delete-and-extra t-region removes the text between point and mark from the bu er and throws it away. You annot get it ba k.

opy-region-as-kill opies the text between point and mark into the kill ring, from whi h you an get it by yanking. The fun tion does not ut or remove the text from the bu er.

8.7 Sear hing Exer ises 



Write an intera tive fun tion that sear hes for a string. If the sear h nds the string, leave point after it and display a message that says \Found!". (Do not use sear h-forward for the name of this fun tion; if you do, you will overwrite the existing version of sear h-forward that omes with Ema s. Use a name su h as test-sear h instead.) Write a fun tion that prints the third element of the kill ring in the e ho area, if any; if the kill ring does not ontain a third element, print an appropriate message.

112

Chapter 8: Cutting and Storing Text

How Lists are Implemented

113

9 How Lists are Implemented In Lisp, atoms are re orded in a straightforward fashion; if the implementation is not straightforward in pra ti e, it is, nonetheless, straightforward in theory. The atom `rose', for example, is re orded as the four ontiguous letters `r', `o', `s', `e'. A list, on the other hand, is kept di erently. The me hanism is equally simple, but it takes a moment to get used to the idea. A list is kept using a series of pairs of pointers. In the series, the rst pointer in ea h pair points to an atom or to another list, and the se ond pointer in ea h pair points to the next pair, or to the symbol nil, whi h marks the end of the list. A pointer itself is quite simply the ele troni address of what is pointed to. Hen e, a list is kept as a series of ele troni addresses. For example, the list (rose violet butter up) has three elements, `rose', `violet', and `butter up'. In the omputer, the ele troni address of `rose' is re orded in a segment of omputer memory along with the address that gives the ele troni address of where the atom `violet' is lo ated; and that address (the one that tells where `violet' is lo ated) is kept along with an address that tells where the address for the atom `butter up' is lo ated. This sounds more ompli ated than it is and is easier seen in a diagram:

nil rose

violet

buttercup

In the diagram, ea h box represents a word of omputer memory that holds a Lisp obje t, usually in the form of a memory address. The boxes, i.e. the addresses, are in pairs. Ea h arrow points to what the address is the address of, either an atom or another pair of addresses. The rst box is the ele troni address of `rose' and the arrow points to `rose'; the se ond box is the address of the next pair of boxes, the rst part of whi h is the address of `violet' and the se ond part of whi h is the address of the next pair. The very last box points to the symbol nil, whi h marks the end of the list. When a variable is set to a list with a fun tion su h as setq, it stores the address of the rst box in the variable. Thus, evaluation of the expression (setq bouquet '(rose violet butter up))

114

Chapter 9: How Lists are Implemented

reates a situation like this: bouquet nil rose

violet

buttercup

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 car

cdr

rose

car

cdr

violet

car cdr butter- nil cup

(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 rose

violet

buttercup

Symbols as a Chest of Drawers

115

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 \Dotted 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.

9.1 Symbols as a Chest of Drawers In an earlier se tion, I suggested that you might imagine a symbol as being a hest of drawers. The fun tion de nition is put in one drawer, the

116

Chapter 9: How Lists are Implemented

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 information. 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: Chest of Drawers

Contents of Drawers

directions to symbol name

map to bouquet

directions to symbol definition

[none]

directions to variable name

map to (rose violet buttercup)

directions to property list

[not described here]

9.2 Exer ise Set flowers to violet and butter up. Cons two more owers on to this list and set this new list to more-flowers. Set the ar of flowers to a sh. What does the more-flowers list now ontain?

The kill-ring-yank-pointer Variable

117

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.)

10.1 Kill Ring Overview The kill ring is a list of textual strings. This is what it looks like: ("some text" "a different pie e of text" "yet more text")

If this were the ontents of my kill ring and I pressed C-y, the string of hara ters saying `some text' would be inserted in this bu er where my

ursor is lo ated. The yank ommand is also used for dupli ating text by opying it. The

opied text is not ut from the bu er, but a opy of it is put on the kill ring and is inserted by yanking it ba k. Three fun tions are used for bringing text ba k from the kill ring: yank, whi h is usually bound to C-y; yank-pop, whi h is usually bound to M-y; and rotate-yank-pointer, whi h is used by the two other fun tions. These fun tions refer to the kill ring through a variable alled the killring-yank-pointer. Indeed, the insertion ode for both the yank and yankpop fun tions is: (insert ( ar kill-ring-yank-pointer))

To begin to understand how yank and yank-pop work, it is rst ne essary to look at the kill-ring-yank-pointer variable and the rotate-yankpointer fun tion.

10.2 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.

118

Chapter 10: Yanking Text Ba k

Thus, if the value of the kill ring is: ("some text" "a different pie e of text" "yet more text")

and the kill-ring-yank-pointer points to the se ond lause, the value of kill-ring-yank-pointer is: ("a different pie e of text" "yet more text")

As explained in the previous hapter (see Chapter 9, \List Implementation", page 113), the omputer does not keep two di erent opies of the text being pointed to by both the kill-ring and the kill-ring-yank-pointer. The words \a di erent pie e of text" and \yet more text" are not dupli ated. Instead, the two Lisp variables point to the same pie es 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 des ribed as if it were a tually what it is omposed 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-yankpointer is spoken of as pointing to a list. These two ways of talking about the same thing sound onfusing at rst but make sense on re e tion. The kill ring is generally thought of as the

omplete stru ture of data that holds the information of what has re ently been ut out of the Ema s bu ers. The kill-ring-yank-pointer on the other hand, serves to indi ate|that is, to `point to'|that part of the kill ring of whi h the rst element (the ar) will be inserted. The rotate-yank-pointer fun tion hanges the element in the kill ring to whi h 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 automati ally sets it to point to the rst element of the kill ring. This is how the list is transformed into a ring. The rotate-yank-pointer fun tion itself is not diÆ ult, but ontains many details. It and the mu h simpler yank and yankpop fun tions are des ribed in an appendix. See Appendix B, \Handling the Kill Ring", page 243.

Exer ises with yank and nth dr

119

10.3 Exer ises with yank and nth dr 



Using C-h v (des ribe-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 ould you have kept more blo ks of text within it? Using nth dr and ar, onstru t a series of expressions to return the rst, se ond, third, and fourth elements of a list.

120

Chapter 10: Yanking Text Ba k

121

while

11 Loops and Re ursion Ema s Lisp has two primary ways to ause an expression, or a series of expressions, to be evaluated repeatedly: one uses a while loop, and the other uses re ursion. Repetition an be very valuable. For example, to move forward four senten es, you need only write a program that will move forward one senten e and then repeat the pro ess four times. Sin e a omputer does not get bored or tired, su h repetitive a tion does not have the deleterious e e ts that ex essive or the wrong kinds of repetition an have on humans. People mostly write Ema s Lisp fun tions using while loops and their kin; but you an use re ursion, whi h provides a very powerful way to think about and then to solve problems1.

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 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 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 trueor-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-falsetest. 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.

11.1.1 A while Loop and a List A ommon way to ontrol 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. Sin e this is an important te hnique, we will reate 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, (), whi h is a synonym for nil or false. On the other hand, a list with elements will return those elements when it is evaluated. Sin e Ema s Lisp onsiders as true any value that is not nil, a list that returns elements will test true in a while loop. For example, you an set the variable empty-list to nil by evaluating the following setq expression: (setq empty-list ())

After evaluating the setq expression, you an evaluate the variable emptylist in the usual way, by pla ing the ursor after the symbol and typing C-x C-e; nil will appear in your e ho 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 an see by evaluating the following two expressions: (setq animals '(gazelle giraffe lion tiger)) 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 expression, 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.

11.1.2 An Example:

print-elements-of-list

The print-elements-of-list fun tion illustrates a while loop with a list. The fun tion requires several lines for its output. If you are reading this in Ema s 21 or a later version, you an evaluate the following expression inside of Info, as usual. If you are using an earlier version of Ema s, you need to opy the ne essary expressions to your `*s rat h*' bu er and evaluate them there. This is be ause the e ho area had only one line in the earlier versions. You an opy the expressions by marking the beginning of the region with C-hSPCi (set-mark- ommand), moving the ursor to the end of the region and then opying the region using M-w ( opy-region-as-kill). In the `*s rat h*' bu er, you an yank the expressions ba k by typing C-y (yank). After you have opied the expressions to the `*s rat h*' bu er, evaluate ea h expression in turn. Be sure to evaluate the last expression, (printelements-of-list animals), by typing C-u C-x C-e, that is, by giving an

124

Chapter 11: Loops and Re ursion

argument to eval-last-sexp. This will ause the result of the evaluation to be printed in the `*s rat h*' bu er instead of being printed in the e ho area. (Otherwise you will see something like this in your e ho area: ^Jgiraffe^J^Jgazelle^J^Jlion^J^Jtiger^Jnil, in whi h ea h `^J' stands for a `newline'.) If you are using Ema s 21 or later, you an evaluate these expressions dire tly in the Info bu er, and the e ho area will grow to show the results. (setq animals '(gazelle giraffe lion tiger)) (defun print-elements-of-list (list) "Print ea h element of LIST on a line of its own." (while list (print ( ar list)) (setq list ( dr list)))) (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.

11.1.3 A Loop with an In rementing Counter A loop is not useful unless it stops when it ought. Besides ontrolling a loop with a list, a ommon way of stopping a loop is to write the rst argument as a test that returns false when the orre t number of repetitions are omplete. This means that the loop must have a ounter|an expression that ounts how many times the loop repeats itself. The test an be an expression su h as (< ount desired-number) whi h returns t for true if the value of ount is less than the desired-number of repetitions and nil for false if the value of ount is equal to or is greater than the desired-number. The expression that in rements the ount an be a simple setq su h as (setq ount (1+ ount)), where 1+ is a builtin fun tion in Ema s Lisp that adds 1 to its argument. (The expression

Example with in rementing ounter

125

(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) body ... (setq ount (1+ ount)))

; true-or-false-test ; in rementer

Note that you need to set the initial value of ount; usually it is set to 1.

Example with in rementing ounter Suppose you are playing on the bea h and de ide to make a triangle of pebbles, putting one pebble in the rst row, two in the se ond 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 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.

The parts of the fun tion de nition The pre eding analysis gives us the bones of our fun tion de nition: rst, we will need a variable that we an all total that will be the total number of pebbles. This will be the value returned by the fun tion. Se ond, we know that the fun tion will require an argument: this argument will be the total number of rows in the triangle. It an be alled number-of-rows. Finally, we need a variable to use as a ounter. We ould all this variable ounter, but a better name is row-number. That is be ause what the ounter does is ount rows, and a program should be written to be as understandable as possible. When the Lisp interpreter rst starts evaluating the expressions in the fun tion, the value of total should be set to zero, sin e we have not added anything to it. Then the fun tion should add the number of pebbles in the rst row to the total, and then add the number of pebbles in the se ond 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 fun tion, so they

an be de lared as lo al 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, sin e we start with the rst row. This means that the let statement will look like this: (let ((total 0) (row-number 1)) body ...)

After the internal variables are de lared and bound to their initial values, we an 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; hen e the row number has to be either less than or equal to the number of rows.)

Putting the fun tion de nition together

127

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 number 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 rownumber variable an be in remented with this expression: (setq row-number (1+ row-number))

Putting the fun tion de nition together We have reated the parts for the fun tion de nition; now we need to put them together. First, the ontents of the while expression: (while (<= row-number number-of-rows) (setq total (+ total row-number)) (setq row-number (1+ row-number)))

; true-or-false-test ; in rementer

Along with the let expression varlist, this very nearly ompletes the body of the fun tion de nition. However, it requires one nal element, the need for whi h is somewhat subtle. The nal tou h is to pla e the variable total on a line by itself after the while expression. Otherwise, the value returned by the whole fun tion 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, whi h is always nil. This may not be evident at rst sight. It almost looks as if the in rementing expression is the last expression of the whole fun tion. But that

128

Chapter 11: Loops and Re ursion

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.

The result of evaluating the let is what is going to be returned by the defun sin e the let is not embedded within any ontaining list, ex ept for the defun as a whole. However, if the while is the last element of the let expression, the fun tion 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 pla ing the symbol as the last element of the list starting with

let. It gets evaluated after the pre eding elements of the list are evaluated,

whi h means it gets evaluated after it has been assigned the orre t 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 se ond 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 fun tion de nition looks like this: ; 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)) (defun triangle (number-of-rows)

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.

11.1.4 Loop with a De rementing Counter Another ommon way to write a while loop is to write the test so that it determines whether a ounter is greater than zero. So long as the ounter is greater than zero, the loop is repeated. But when the ounter is equal to or less than zero, the loop is stopped. For this to work, the ounter has to start out greater than zero and then be made smaller and smaller by a form that is evaluated repeatedly. The test will be an expression su h as (> ounter 0) whi h returns t for true if the value of ounter is greater than zero, and nil for false if the value of ounter is equal to or less than zero. The expression that makes the number smaller and smaller an be a simple setq su h as (setq ounter (1- ounter)), where 1- is a built-in fun tion in Ema s Lisp that subtra ts 1 from its argument. The template for a de rementing while loop looks like this: (while (> ounter 0) body ... (setq ounter (1- ounter)))

; true-or-false-test ; de rementer

Example with de rementing ounter To illustrate a loop with a de rementing ounter, we will rewrite the

triangle fun tion so the ounter de reases to zero.

This is the reverse of the earlier version of the fun tion. In this ase, to nd 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 pre eding row, 2, and then add the total of those two rows to the row that pre edes them, whi h is 1. Likewise, to nd 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 pre eding row, whi h is 6, and then add the total of those two rows to the row that pre edes them, whi h is 5, and so on. As in the previous example, ea h 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 pro ess of adding two numbers is repeated again and again until there are no more pebbles to add.

130

Chapter 11: Loops and Re ursion

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.

The parts of the fun tion de nition 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, whi h is what we want to al ulate. These variables an be named number-of-rows, number-of-pebbles-in-row, and total, respe tively. Both total and number-of-pebbles-in-row are used only inside the fun tion and are de lared with let. The initial value of total should, of

ourse, be zero. However, the initial value of number-of-pebbles-in-row should be equal to the number of rows in the triangle, sin e 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 an 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 numberof-pebbles-in-row should be de remented by one, sin e the next time the loop repeats, the pre eding row will be added to the total. The number of pebbles in a pre eding row is one less than the number of pebbles in a row, so the built-in Ema s Lisp fun tion 1- an be used to

ompute the number of pebbles in the pre eding row. This an 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)

Putting the fun tion de nition together We an put these expressions together to reate a fun tion de nition that works. However, on examination, we nd that one of the lo al variables is unneeded!

Save your time: dolist and dotimes

131

The fun tion de nition looks like this:

;;; First subtra tive 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 fun tion works. However, we do not need number-of-pebbles-in-row. When the triangle fun tion is evaluated, the symbol number-of-rows will be bound to a number, giving it an initial value. That number an be

hanged in the body of the fun tion as if it were a lo al variable, without any fear that su h a hange will e e t the value of the variable outside of the fun tion. This is a very useful hara teristi of Lisp; it means that the variable number-of-rows an be used anywhere in the fun tion where number-of-pebbles-in-row is used. Here is a se ond version of the fun tion written a bit more leanly: (defun triangle (number) ; Se ond version. "Return sum of numbers 1 through NUMBER in lusive." (let ((total 0)) (while (> number 0) (setq total (+ total number)) (setq number (1- number))) total))

In brief, a properly written while loop will onsist of three parts: 1. A test that will return false after the loop has repeated itself the orre t number of times. 2. An expression the evaluation of whi h will return the value desired after being repeatedly evaluated. 3. An expression to hange 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.

11.2 Save your time:

dolist

and dotimes

In addition to while, both dolist and dotimes provide for looping. Sometimes these are qui ker to write than the equivalent while loop. Both are Lisp ma ros. (See se tion \Ma ros" in The GNU Ema s Lisp Referen e Manual. )

132

Chapter 11: Loops and Re ursion

dolist works like a while loop that ` drs down a list': dolist automati 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)) (defun reverse-list-with-while (list) "Using while, reverse the order of LIST." (let (value) ; make sure list starts empty (while list (setq value ( ons ( ar list) value)) (setq list ( dr list))) value)) (reverse-list-with-while animals)

And here is how you ould use the dolist ma ro: (setq animals '(gazelle giraffe lion tiger)) (defun reverse-list-with-dolist (list) "Using dolist, reverse the order of LIST." (let (value) ; make sure list starts empty (dolist (element list value) (setq value ( ons element value))))) (reverse-list-with-dolist animals)

In Info, you an pla e your ursor after the losing parenthesis of ea h expression 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)) expression 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 automati 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

Here is an example of a defun that uses dotimes to add up the number of pebbles in a triangle. (defun triangle-using-dotimes (number-of-rows) "Using dotimes, add up the number of pebbles in a triangle." (let ((total 0)) ; otherwise a total is a void variable (dotimes (number number-of-rows total) (setq total (+ total (1+ number)))))) (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 arguments' will be ome suÆ iently di erent from the rst arguments that the nal instan e will stop.

11.3.1 Building Robots: Extending the Metaphor It is sometimes helpful to think of a running program as a robot that does a job. In doing its job, a re ursive fun tion alls on a se ond robot to help it. The se ond robot is identi al to the rst in every way, ex ept that the se ond robot helps the rst and has been passed di erent arguments than the rst. In a re ursive fun tion, the se ond robot may all a third; and the third may all a fourth, and so on. Ea h of these is a di erent entity; but all are

lones. Sin e ea h robot has slightly di erent instru tions|the arguments will di er from one robot to the next|the last robot should know when to stop. Let's expand on the metaphor in whi h a omputer program is a robot. A fun tion de nition provides the blueprints for a robot. When you install a fun tion de nition, that is, when you evaluate a defun spe ial form, you install the ne essary equipment to build robots. It is as if you were in a fa tory, setting up an assembly line. Robots with the same name are built a

ording to the same blueprints. So they have, as it were, the same `model number', but a di erent `serial number'. We often say that a re ursive fun tion ` alls itself'. What we mean is that the instru tions in a re ursive fun tion ause the Lisp interpreter to run a di erent fun tion that has the same name and does the same job as the rst, but with di erent arguments.

Re ursion with a List

135

It is important that the arguments di er from one instan e to the next; otherwise, the pro ess will never stop.

11.3.2 The Parts of a Re ursive De nition A re ursive fun tion typi ally ontains a onditional expression whi h has three parts: 1. A true-or-false-test that determines whether the fun tion is alled again, here alled the do-again-test. 2. The name of the fun tion. When this name is alled, a new instan e of the fun tion|a new robot, as it were|is reated and told what to do. 3. An expression that returns a di erent value ea h time the fun tion is

alled, here alled the next-step-expression. Consequently, the argument (or arguments) passed to the new instan e of the fun tion will be di erent from that passed to the previous instan e. This auses the

onditional expression, the do-again-test, to test false after the orre t number of repetitions. Re ursive fun tions an be mu h simpler than any other kind of fun tion. Indeed, when people rst start to use them, they often look so mysteriously simple as to be in omprehensible. Like riding a bi y le, reading a re ursive fun tion de nition takes a ertain kna k whi h is hard at rst but then seems simple. There are several di erent ommon re ursive patterns. A very simple pattern looks like this: (defun name-of-re ursive-fun tion (argument-list) "do umentation..." (if do-again-test body ... (name-of-re ursive-fun tion next-step-expression)))

Ea h time a re ursive fun tion is evaluated, a new instan e of it is reated and told what to do. The arguments tell the instan e what to do. An argument is bound to the value of the next-step-expression. Ea h instan e runs with a di erent value of the next-step-expression. The value in the next-step-expression is used in the do-again-test. The value returned by the next-step-expression is passed to the new instan e of the fun tion, whi h evaluates it (or some transmogri ation of it) to determine whether to ontinue or stop. The next-step-expression is designed so that the do-again-test returns false when the fun tion should no longer be repeated. The do-again-test is sometimes alled the stop ondition, sin e it stops the repetitions when it tests false.

136

Chapter 11: Loops and Re ursion

11.3.3 Re ursion with a List The example of a while loop that printed the elements of a list of numbers

an be written re ursively. Here is the ode, in luding an expression to set the value of the variable animals to a list. If you are using Ema s 20 or before, this example must be opied to the `*s rat h*' bu er and ea h expression must be evaluated there. Use C-u Cx C-e to evaluate the (print-elements-re ursively animals) expression so that the results are printed in the bu er; otherwise the Lisp interpreter will try to squeeze the results into the one line of the e ho area. Also, pla e your ursor immediately after the last losing parenthesis of the print-elements-re ursively fun tion, before the omment. Otherwise, the Lisp interpreter will try to evaluate the omment. If you are using Ema s 21 or later, you an evaluate this expression dire tly in Info. (setq animals '(gazelle giraffe lion tiger)) (defun print-elements-re ursively (list) "Print ea h element of LIST on a line of its own. Uses re ursion." (if list ; do-again-test (progn (print ( ar list)) ; body (print-elements-re ursively ; re ursive all ( dr list))))) ; next-step-expression (print-elements-re ursively animals)

The print-elements-re ursively fun tion rst tests whether there is any ontent in the list; if there is, the fun tion prints the rst element of the list, the ar of the list. Then the fun tion `invokes itself', but gives itself as its argument, not the whole list, but the se ond and subsequent elements of the list, the dr of the list. Put another way, if the list is not empty, the fun tion invokes another instan e of ode that is similar to the initial ode, but is a di erent thread of exe ution, with di erent arguments than the rst instan e. Put in yet another way, if the list is not empty, the rst robot assemblies a se ond robot and tells it what to do; the se ond robot is a di erent individual from the rst, but is the same model. When the se ond evaluation o

urs, the if expression is evaluated and if true, prints the rst element of the list it re eives as its argument (whi h is the se ond element of the original list). Then the fun tion ` alls itself' with the dr of the list it is invoked with, whi h (the se ond time around) is the

dr of the dr of the original list.

Re ursion in Pla e of a Counter

137

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

11.3.4 Re ursion in Pla e of a Counter The triangle fun tion des ribed in a previous se tion an also be written re ursively. It looks like this: (defun triangle-re ursively (number) "Return the sum of the numbers 1 through NUMBER in lusive. Uses re ursion." (if (= number 1) ; do-again-test 1 ; then-part (+ number ; else-part (triangle-re ursively ; re ursive all (1- number))))) ; next-step-expression (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

then-part of the if expression, whi h returns the number 1 as the value of the fun tion. (A triangle with one row has one pebble in it.) Suppose, however, that the value of the argument is 2. In this ase, Ema s evaluates the else-part of the if expression. The else-part onsists of an addition, the re ursive all to trianglere ursively and a de rementing a tion; and it looks like this: (+ number (triangle-re ursively (1- number)))

When Ema s evaluates this expression, the innermost expression is evaluated rst; then the other parts in sequen e. Here are the steps in detail: Step 1 Evaluate the innermost expression. The innermost expression is (1- number) so Ema s de rements the value of number from 2 to 1. Step 2 Evaluate the triangle-re ursively fun tion. The Lisp interpreter reates an individual instan e of trianglere ursively. It does not matter that this fun tion is ontained within itself. Ema s passes the result Step 1 as the argument used by this instan e of the triangle-re ursively fun tion In this ase, Ema s evaluates triangle-re ursively with an argument of 1. This means that this evaluation of trianglere ursively returns 1. Step 3 Evaluate the value of number. The variable number is the se ond element of the list that starts with +; its value is 2. Step 4 Evaluate the + expression. The + expression re eives two arguments, the rst from the evaluation of number (Step 3) and the se ond from the evaluation of triangle-re ursively (Step 2). The result of the addition is the sum of 2 plus 1, and the number 3 is returned, whi h is orre t. A triangle with two rows has three pebbles in it.

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

Step 3 Evaluate the triangle-re ursively fun tion. The number 2 is passed to the triangle-re ursively fun tion. We know what happens when Ema s evaluates trianglere ursively with an argument of 2. After going through the sequen e of a tions des ribed 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 whi h the fun tion was alled, whi h is 3. The value returned by the fun tion as a whole will be 6. Now that we know what will happen when triangle-re ursively is

alled with an argument of 3, it is evident what will happen if it is alled with an argument of 4: In the re ursive all, the evaluation of (triangle-re ursively (1- 4))

will return the value of evaluating (triangle-re ursively 3)

whi h is 6 and this value will be added to 4 by the addition in the third line. The value returned by the fun tion as a whole will be 10. Ea h time triangle-re ursively is evaluated, it evaluates a version of itself|a di erent instan e of itself|with a smaller argument, until the argument is small enough so that it does not evaluate itself. Note that this parti ular design for a re ursive fun tion requires that operations be deferred. Before (triangle-re ursively 7) an al ulate its answer, it must all (triangle-re ursively 6); and before (triangle-re ursively 6) an

al ulate its answer, it must all (triangle-re ursively 5); and so on. That is to say, the al ulation that (triangle-re ursively 7) makes must be deferred until (triangle-re ursively 6) makes its al ulation; and (triangle-re ursively 6) must defer until (triangle-re ursively 5)

ompletes; and so on. If ea h of these instan es of triangle-re ursively are thought of as di erent robots, the rst robot must wait for the se ond to omplete its job, whi h must wait until the third ompletes, and so on. There is a way around this kind of waiting, whi h we will dis uss in Se tion 11.3.7, \Re ursion without Deferments", page 143.

11.3.5 Re ursion Example Using ond The version of triangle-re ursively des ribed earlier is written with the if spe ial form. It an also be written using another spe ial form alled

140

Chapter 11: Loops and Re ursion

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 onsequent, 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 onsequent of that expression is evaluated. The onsequent 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 (triangleusing- ond (1- number))) if the number is greater than 1.

11.3.6 Re ursive Patterns Here are three ommon re ursive patterns. Ea h involves a list. Re ursion does not need to involve lists, but Lisp is designed for lists and this provides a sense of its primal apabilities.

Re ursive Pattern: every

141

Re ursive Pattern: every In the every re ursive pattern, an a tion is performed on every element of a list. The basi pattern is:

 

If a list be empty, return nil. Else, a t on the beginning of the list (the ar of the list) through a re ursive all by the fun tion on the rest (the dr) of the list, and, optionally, ombine the a ted-on element, using ons, with the results of a ting on the rest. 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)

If numbers-list is empty, do nothing. But if it has ontent, onstru t a list

ombining the square of the rst number in the list with the result of the re ursive all. (The example follows the pattern exa tly: nil is returned if the numbers' list is empty. In pra ti e, you would write the onditional so it arries out the a tion when the numbers' list is not empty.) The print-elements-re ursively fun tion (see Se tion 11.3.3, \Re ursion with a List", page 136) is another example of an every pattern, ex ept in this ase, rather than bring the results together using ons, we print ea h element of output. The print-elements-re ursively fun tion looks like this: (setq animals '(gazelle giraffe lion tiger))

142

Chapter 11: Loops and Re ursion (defun print-elements-re ursively (list) "Print ea h element of LIST on a line of its own. Uses re ursion." (if list ; do-again-test (progn (print ( ar list)) ; body (print-elements-re ursively ; re ursive all ( dr list))))) ; next-step-expression (print-elements-re ursively animals)

The pattern for print-elements-re ursively is:  If the list be empty, do nothing.  But if the list has at least one element, a t on the beginning of the list (the ar of the list), and make a re ursive all on the rest (the dr) of the list.

Re ursive Pattern: a

umulate Another re ursive pattern is alled the a

umulate pattern. In the a

umulate re ursive pattern, an a tion is performed on every element of a

list and the result of that a tion is a

umulated with the results of performing the a tion on the other elements. This is very like the `every' pattern using ons, ex ept that ons is not used, but some other ombiner. The pattern is:  If a list be empty, return zero or some other onstant.  Else, a t on the beginning of the list (the ar of the list), and ombine that a ted-on element, using + or some other ombining fun tion, with a re ursive all by the fun tion on the rest (the dr) of the list. Here is an example: (defun add-elements (numbers-list) "Add the elements of NUMBERS-LIST together." (if (not numbers-list) 0 (+ ( ar numbers-list) (add-elements ( dr numbers-list))))) (add-elements '(1 2 3 4)) ) 10

See Se tion 14.9.2, \Making a List of Files", page 194, for an example of the a

umulate pattern.

Re ursion without Deferments

143

Re ursive Pattern: keep A third re ursive pattern is alled the keep pattern. In the keep re ursive pattern, ea h element of a list is tested; the element is a ted on and the results are kept only if the element meets a riterion. Again, this is very like the `every' pattern, ex ept the element is skipped unless it meets a riterion. The pattern has three parts:  If a list be empty, return nil.  Else, if the beginning of the list (the ar of the list) passes a test a t on that element and ombine it, using ons with a re ursive all by the fun tion on the rest (the dr) of the list.  Otherwise, if the beginning of the list (the ar of the list) fails the test skip on that element, and, re ursively all the fun tion on the rest (the dr) of the list. Here is an example that uses ond: (defun keep-three-letter-words (word-list) "Keep three letter words in WORD-LIST." ( ond ;; First do-again-test: stop- ondition ((not word-list) nil) ;; Se ond do-again-test: when to a t ((eq 3 (length (symbol-name ( ar word-list)))) ;; ombine a ted-on element with re ursive all on shorter list ( ons ( ar word-list) (keep-three-letter-words ( dr word-list)))) ;; Third do-again-test: when to skip element; ;; re ursively all shorter list with next-step expression (t (keep-three-letter-words ( dr word-list))))) (keep-three-letter-words '(one two three four five six)) ) (one two six)

It goes without saying that you need not use nil as the test for when to stop; and you an, of ourse, ombine these patterns.

11.3.7 Re ursion without Deferments Let's onsider again what happens with the triangle-re ursively fun tion. We will nd that the intermediate al ulations are deferred until all

an be done.

144

Chapter 11: Loops and Re ursion

Here is the fun tion de nition: (defun triangle-re ursively (number) "Return the sum of the numbers 1 through NUMBER in lusive. Uses re ursion." (if (= number 1) ; do-again-test 1 ; then-part (+ number ; else-part (triangle-re ursively ; re ursive all (1- number))))) ; next-step-expression

What happens when we all this fun tion with a argument of 7? The rst instan e of the triangle-re ursively fun tion adds the number 7 to the value returned by a se ond instan e of triangle-re ursively, an instan e that has been passed an argument of 6. That is to say, the rst

al ulation is: (+ 7 (triangle-re ursively 6)

The rst instan e of triangle-re ursively|you may want to think of it as a little robot| annot omplete its job. It must hand o the al ulation for (triangle-re ursively 6) to a se ond instan e of the program, to a se ond robot. This se ond individual is ompletely di erent from the rst one; it is, in the jargon, a `di erent instantiation'. Or, put another way, it is a di erent robot. It is the same model as the rst; it al ulates triangle numbers re ursively; but it has a di erent serial number. And what does (triangle-re ursively 6) return? It returns the number 6 added to the value returned by evaluating triangle-re ursively with an argument of 5. Using the robot metaphor, it asks yet another robot to help it. Now the total is: (+ 7 6 (triangle-re ursively 5)

And what happens next? (+ 7 6 5 (triangle-re ursively 4)

Ea h time triangle-re ursively is alled, ex ept for the last time, it reates another instan e of the program|another robot|and asks it to make a al ulation. Eventually, the full addition is set up and performed: (+ 7 6 5 4 3 2 1)

This design for the fun tion defers the al ulation of the rst step until the se ond an be done, and defers that until the third an be done, and so on. Ea h deferment means the omputer must remember what is being waited on. This is not a problem when there are only a few steps, as in this example. But it an be a problem when there are more steps.

No Deferment Solution

145

11.3.8 No Deferment Solution The solution to the problem of deferred operations is to write in a manner that does not defer operations2. This requires writing to a di erent pattern, often one that involves writing two fun tion de nitions, an `initialization' fun tion and a `helper' fun tion. The `initialization' fun tion sets up the job; the `helper' fun tion does the work. Here are the two fun tion de nitions for adding up numbers. They are so simple, I nd them hard to understand. (defun triangle-initialization (number) "Return the sum of the numbers 1 through NUMBER in lusive. This is the `initialization' omponent of a two fun tion duo that uses re ursion." (triangle-re ursive-helper 0 0 number)) (defun triangle-re ursive-helper (sum ounter number) "Return SUM, using COUNTER, through NUMBER in lusive. This is the `helper' omponent of a two fun tion duo that uses re ursion." (if (> ounter number) sum (triangle-re ursive-helper (+ sum ounter) ; sum (1+ ounter) ; ounter number))) ; number

Install both fun tion de nitions by evaluating them, then all triangle-

initialization with 2 rows:

(triangle-initialization 2) ) 3

The `initialization' fun tion alls the rst instan e of the `helper' fun tion with three arguments: zero, zero, and a number whi h is the number of rows in the triangle. The rst two arguments passed to the `helper' fun tion are initialization values. These values are hanged when triangle-re ursive-helper invokes new instan es.3 2 3

The phrase tail re ursive is used to des ribe su h a pro ess, one that uses ` onstant spa e'. The jargon is mildly onfusing: triangle-re ursive-helper uses a pro ess that is iterative in a pro edure that is re ursive. The pro ess is alled iterative be ause the

omputer need only re ord the three values, sum, ounter, and number; the pro edure is re ursive be ause the fun tion ` alls itself'. On the other hand, both the pro ess and the pro edure used by triangle-re ursively are alled re ursive. The word `re ursive' has di erent meanings in the two ontexts.

146

Chapter 11: Loops and Re ursion

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) (1+ 0) 1)

whi h is:

; sum ; ounter ; number

(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.

11.4 Looping Exer ise 

  

Write a fun tion similar to triangle in whi h ea h row has a value whi h is the square of the row number. Use a while loop. Write a fun tion similar to triangle that multiplies instead of adds the values. Rewrite these two fun tions re ursively. Rewrite these fun tions using

ond. Write a fun tion for Texinfo mode that reates an index entry at the beginning of a paragraph for every `dfn' within the paragraph. (In a Texinfo le, `dfn' marks a de nition. For more information, see \Indi ating De nitions, Commands, et ." in Texinfo, The GNU Do umentation Format.)

148

Chapter 11: Loops and Re ursion

The Regular Expression for senten e-end

149

12 Regular Expression Sear hes Regular expression sear hes are used extensively in GNU Ema s. The two fun tions, forward-senten e and forward-paragraph, illustrate these sear hes well. They use regular expressions to nd where to move point. The phrase `regular expression' is often written as `regexp'. Regular expression sear hes are des ribed in se tion \Regular Expression Sear h" in The GNU Ema s Manual, as well as in se tion \Regular Expressions" in The GNU Ema s Lisp Referen e Manual. In writing this hapter, I am presuming that you have at least a mild a quaintan e with them. The major point to remember is that regular expressions permit you to sear h for patterns as well as for literal strings of hara ters. For example, the ode in forward-senten e sear hes for the pattern of possible hara ters that

ould mark the end of a senten e, and moves point to that spot. Before looking at the ode for the forward-senten e fun tion, it is worth

onsidering what the pattern that marks the end of a senten e must be. The pattern is dis ussed in the next se tion; following that is a des ription of the regular expression sear h fun tion, re-sear h-forward. The forward-senten e fun tion is des ribed in the se tion following. Finally, the forward-paragraph fun tion is des ribed in the last se tion of this hapter. forward-paragraph is a omplex fun tion that introdu es several new features.

12.1 The Regular Expression for senten e-end The symbol senten e-end is bound to the pattern that marks the end of a senten e. What should this regular expression be? Clearly, a senten e may be ended by a period, a question mark, or an ex lamation mark. Indeed, only lauses that end with one of those three

hara ters should be onsidered the end of a senten e. This means that the pattern should in lude the hara ter set: [.?!â„„

However, we do not want forward-senten e merely to jump to a period, a question mark, or an ex lamation mark, be ause su h a hara ter might be used in the middle of a senten e. A period, for example, is used after abbreviations. So other information is needed. A

ording to onvention, you type two spa es after every senten e, but only one spa e after a period, a question mark, or an ex lamation mark in the body of a senten e. So a period, a question mark, or an ex lamation mark followed by two spa es is a good indi ator of an end of senten e. However, in a le, the two spa es may instead be a tab or the end of a line. This means that the regular expression should in lude these three items as alternatives.

150

Chapter 12: Regular Expression Sear hes

This group of alternatives will look like this: \\($\\| \\| \\) ^ ^^ TAB SPC

Here, `$' indi ates the end of the line, and I have pointed out where the tab and two spa es are inserted in the expression. Both are inserted by putting the a tual hara ters into the expression. Two ba kslashes, `\\', are required before the parentheses and verti al bars: the rst ba kslash quotes the following ba kslash in Ema s; and the se ond indi ates that the following hara ter, the parenthesis or the verti al bar, is spe ial. Also, a senten e may be followed by one or more arriage returns, like this: [ â„„*

Like tabs and spa es, a arriage return is inserted into a regular expression by inserting it literally. The asterisk indi ates that the hRETi is repeated zero or more times. But a senten e end does not onsist only of a period, a question mark or an ex lamation mark followed by appropriate spa e: a losing quotation mark or a losing bra e of some kind may pre ede the spa e. Indeed more than one su h mark or bra e may pre ede the spa e. These require a expression that looks like this: [â„„\"')}â„„*

In this expression, the rst `â„„' is the rst hara ter in the expression; the se ond hara ter is `"', whi h is pre eded by a `\' to tell Ema s the `"' is not spe ial. The last three hara ters are `'', `)', and `}'. All this suggests what the regular expression pattern for mat hing the end of a senten e should be; and, indeed, if we evaluate senten e-end we nd that it returns the following value: senten e-end ) "[.?!â„„[â„„\"')}â„„*\\($\\| â„„*"

\\|

\\)[

12.2 The re-sear h-forward Fun tion The re-sear h-forward fun tion is very like the sear h-forward fun tion. (See Se tion 8.1.3, \The sear h-forward Fun tion", page 92.) re-sear h-forward sear hes for a regular expression. If the sear h is su

essful, it leaves point immediately after the last hara ter in the target. If the sear h is ba kwards, it leaves point just before the rst hara ter in the target. You may tell re-sear h-forward to return t for true. (Moving point is therefore a `side e e t'.)

151

forward-senten e

Like sear h-forward, the re-sear h-forward fun tion takes four arguments: 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 forwardsenten 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

Here is the ode for forward-senten e: (defun forward-senten e (&optional arg) "Move forward to next senten e-end. With argument, repeat. With negative argument, move ba kward repeatedly to senten e-beginning. Senten e ends are identified by the value of senten e-end treated as a regular expression. Also, every paragraph boundary terminates senten es as well." (intera tive "p") (or arg (setq arg 1)) (while (< arg 0) (let ((par-beg (save-ex ursion (start-of-paragraph-text) (point)))) (if (re-sear h-ba kward ( on at senten e-end "[^ \t\nâ„„") par-beg t) (goto- har (1- (mat h-end 0))) (goto- har par-beg))) (setq arg (1+ arg))) (while (> arg 0) (let ((par-end (save-ex ursion (end-of-paragraph-text) (point)))) (if (re-sear h-forward senten e-end par-end t) (skip- hars-ba kward " \t\n") (goto- har par-end))) (setq arg (1- arg))))

The fun tion looks long at rst sight and it is best to look at its skeleton rst, and then its mus le. The way to see the skeleton is to look at the expressions that start in the left-most olumns: (defun forward-senten e (&optional arg) "do umentation..." (intera tive "p") (or arg (setq arg 1)) (while (< arg 0)

body-of-while-loop

(while (> arg 0)

body-of-while-loop

This looks mu h simpler! The fun tion de nition onsists of do umentation, an intera tive expression, an or expression, and while loops. Let's look at ea h of these parts in turn. We note that the do umentation is thorough and understandable. The fun tion has an intera tive "p" de laration. This means that the pro essed pre x argument, if any, is passed to the fun tion as its argument. (This will be a number.) If the fun tion is not passed an argument (it is optional) then the argument arg will be bound to 1. When forward-

The while loops

153

senten e is alled non-intera tively without an argument, arg is bound to nil. The or expression handles the pre x argument. What it does is either leave the value of arg as it is, but only if arg is bound to a value; or it sets the value of arg to 1, in the ase when arg is bound to nil.

The while loops Two while loops follow the or expression. The rst while has a trueor-false-test that tests true if the pre x argument for forward-senten e is a negative number. This is for going ba kwards. The body of this loop is similar to the body of the se ond while lause, but it is not exa tly the same. We will skip this while loop and on entrate on the se ond while loop. The se ond while loop is for moving point forward. Its skeleton looks like this: (while (> arg 0) (let varlist (if (true-or-false-test)

then-part else-part

(setq arg (1- arg))))

; true-or-false-test

; while loop de rementer

The while loop is of the de rementing kind. (See Se tion 11.1.4, \A Loop with a De rementing Counter", page 129.) It has a true-or-false-test that tests true so long as the ounter (in this ase, the variable arg) is greater than zero; and it has a de rementer that subtra ts 1 from the value of the

ounter every time the loop repeats. If no pre x argument is given to forward-senten e, whi h is the most

ommon way the ommand is used, this while loop will run on e, sin e the value of arg will be 1. The body of the while loop onsists of a let expression, whi h reates and binds a lo al variable, and has, as its body, an if expression. The body of the while loop looks like this: (let ((par-end (save-ex ursion (end-of-paragraph-text) (point)))) (if (re-sear h-forward senten e-end par-end t) (skip- hars-ba kward " \t\n") (goto- har par-end)))

The let expression reates and binds the lo al variable par-end. As we shall see, this lo al variable is designed to provide a bound or limit to the regular expression sear h. If the sear h fails to nd a proper senten e ending in the paragraph, it will stop on rea hing the end of the paragraph.

154

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 forwardsenten e fun tion buried here, but this is a ommon way this kind of operation 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 resear 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 illustrated 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.

12.4

forward-paragraph:

a Goldmine of Fun tions

The forward-paragraph fun tion moves point forward to the end of the paragraph. It is usually bound to M-} and makes use of a number of fun tions that are important in themselves, in luding let*, mat h-beginning, and looking-at. The fun tion de nition for forward-paragraph is onsiderably longer than the fun tion de nition for forward-senten e be ause it works with a paragraph, ea h line of whi h may begin with a ll pre x. A ll pre x onsists of a string of hara ters that are repeated at the beginning of ea h line. For example, in Lisp ode, it is a onvention to start ea h line of a paragraph-long omment with `;;; '. In Text mode, four blank spa es make up another ommon ll pre x, reating an indented paragraph. (See se tion \Fill Pre x" in The GNU Ema s Manual, for more information about ll pre xes.) The existen e of a ll pre x means that in addition to being able to nd the end of a paragraph whose lines begin on the left-most olumn, the forward-paragraph fun tion must be able to nd the end of a paragraph when all or many of the lines in the bu er begin with the ll pre x. Moreover, it is sometimes pra ti al to ignore a ll pre x that exists, espe ially when blank lines separate paragraphs. This is an added ompli ation. Rather than print all of the forward-paragraph fun tion, we will only print parts of it. Read without preparation, the fun tion an be daunting! In outline, the fun tion looks like this: (defun forward-paragraph (&optional arg) "do umentation..." (intera tive "p") (or arg (setq arg 1)) (let*

varlist

(while (< arg 0) ; ba kward-moving- ode ... (setq arg (1+ arg))) (while (> arg 0) ; forward-moving- ode ... (setq arg (1- arg)))))

156

Chapter 12: Regular Expression Sear hes

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 argument 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.

The let* expression The next line of the forward-paragraph fun tion begins a let* expression. This is a di erent kind of expression than we have seen so far. The symbol is let* not let. The let* spe ial form is like let ex ept that Ema s sets ea h variable in sequen e, one after another, and variables in the latter part of the varlist

an make use of the values to whi h Ema s set variables in the earlier part of the varlist. In the let* expression in this fun tion, Ema s binds two variables: fillprefix-regexp and paragraph-separate. The value to whi h paragraphseparate is bound depends on the value of fill-prefix-regexp. Let's look at ea h in turn. The symbol fill-prefix-regexp is set to the value returned by evaluating the following list: (and fill-prefix (not (equal fill-prefix "")) (not paragraph-ignore-fill-prefix) (regexp-quote fill-prefix))

This is an expression whose rst element is the and spe ial form. As we learned earlier (see \The kill-new fun tion", page 105), 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 Lisp.) In other words, an and expression returns a true value only if all its arguments are true. In this ase, the variable fill-prefix-regexp is bound to a non-nil value only if the following four expressions produ e a true (i.e., a non-nil) value when they are evaluated; otherwise, fill-prefix-regexp is bound to nil.

The let* expression

157

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-ignorefill-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 evaluating 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 fillprefix-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-orfalse-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 elsepart 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 thenpart of the if expression and binds paragraph-separate to a regular expression 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 paragraph separate regular expression on atenated with an alternative expression 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 optional 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.

The forward motion while loop The se ond part of the body of the let* deals with forward motion. It is a while loop that repeats itself so long as the value of arg is greater than zero. In the most ommon use of the fun tion, the value of the argument is 1, so the body of the while loop is evaluated exa tly on e, and the ursor moves forward one paragraph. This part handles three situations: when point is between paragraphs, when point is within a paragraph and there is a ll pre x, and when point is within a paragraph and there is no ll pre x. The while loop looks like this: (while (> arg 0) (beginning-of-line) ;; 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)))) (setq arg (1- arg)))

We an see immediately that this is a de rementing ounter while loop, using the expression (setq arg (1- arg)) as the de rementer.

Between paragraphs

159

The body of the loop onsists of three expressions: ;; between paragraphs (beginning-of-line) (while body-of-while )

;; within paragraphs, with ll pre x (if true-or-false-test

then-part

;; within paragraphs, no ll pre x

else-part

When the Ema s Lisp interpreter evaluates the body of the while loop, the rst thing it does is evaluate the (beginning-of-line) expression and move point to the beginning of the line. Then there is an inner while loop. This while loop is designed to move the ursor out of the blank spa e between paragraphs, if it should happen to be there. Finally, there is an if expression that a tually moves point to the end of the paragraph.

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 following the ursor mark the separation between two paragraphs, then the and expression is true. After evaluating the and expression, the Lisp interpreter 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-prefixregexp 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 hbeginning 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 separating line.

162

Chapter 12: Regular Expression Sear hes



But if there is no ll pre x, | Sear h for the next paragraph start pattern. | Go to the beginning of the paragraph start pattern, whi h will be the end of the previous paragraph. | Or else go to the end of the a

essible portion of the bu er. For review, here is the ode we have just been dis ussing, formatted for

larity: (intera tive "p") (or arg (setq arg 1)) (let* ( (fill-prefix-regexp (and fill-prefix (not (equal fill-prefix "")) (not paragraph-ignore-fill-prefix) (regexp-quote fill-prefix))) (paragraph-separate (if fill-prefix-regexp ( on at paragraph-separate "\\|^" fill-prefix-regexp "[ \tâ„„*$") paragraph-separate)))

omitted-ba kward-moving- ode ... (while (> arg 0) (beginning-of-line)

; forward-moving- ode

(while (prog1 (and (not (eobp)) (looking-at paragraph-separate)) (forward-line 1))) (if fill-prefix-regexp (while (and (not (eobp)) ; then-part (not (looking-at paragraph-separate)) (looking-at fill-prefix-regexp)) (forward-line 1)) ; else-part: the inner-if (if (re-sear h-forward paragraph-start nil t) (goto- har (mat h-beginning 0)) (goto- har (point-max)))) (setq arg (1- arg)))))

; de rementer

The full de nition for the forward-paragraph fun tion not only in ludes this ode for going forwards, but also ode for going ba kwards.

Create Your Own `TAGS' File

163

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 dire 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.

12.5 Create Your Own `TAGS' File The M-. (find-tag) ommand takes you dire tly to the sour e for a fun tion, variable, node, or other sour e. The fun tion depends on tags tables to tell it where to go. You often need to build and install tags tables yourself. They are not built automati ally. A tags table is alled a `TAGS' le; the name is in upper

ase letters. You an reate a `TAGS' le by alling the etags program that omes as a part of the Ema s distribution. Usually, etags is ompiled and installed when Ema s is built. (etags is not an Ema s Lisp fun tion or a part of Ema s; it is a C program.) To reate a `TAGS' le, rst swit h to the dire tory in whi h you want to reate the le. In Ema s you an do this with the M-x d ommand, or by visiting a le in the dire tory, or by listing 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

to reate a `TAGS' le. For example, if you have a large number of les in your `~/ema s' dire tory, as I do|I have 137 `.el' les in it, of whi h I load 12|you an reate a `TAGS' le for the Ema s Lisp les in that dire tory. The etags program takes all the usual shell `wild ards'. For example, if you have two dire tories for whi h you want a single `TAGS file', type etags *.el ../elisp/*.el, where `../elisp/' is the se ond dire tory: M-x ompile RET etags *.el ../elisp/*.el RET

164

Chapter 12: Regular Expression Sear hes

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 visittags-table ommand to spe ify it. Otherwise, you will need to reate the tag table yourself and then use M-x visit-tags-table.

Building Tags in the Ema s sour es The GNU Ema s sour es ome with a `Makefile' that ontains a sophisti ated etags ommand that reates, olle ts, and merges tags tables from all over the Ema s sour es and puts the information into one `TAGS' le in the `sr /' dire tory below the top level of your Ema s sour e dire tory. To build this `TAGS' le, go to the top level of your Ema s sour e dire tory and run the ompile ommand make tags: M-x ompile RET make tags RET

(The make tags ommand works well with the GNU Ema s sour es, as well as with some other sour e pa kages.) For more information, see se tion \Tag Tables" in The GNU Ema s Manual.

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

let*

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 negative, the sear h goes ba kwards. Bind some variables lo ally to parti ular values, and then evaluate 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 eobp

Return t for true if the text after point mat hes the argument, whi h should be a regular expression. 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

prog1

Evaluate ea h argument in sequen e and then return the value of the rst. For example: (prog1 1 2 3 4) ) 1

12.7 Exer ises with re-sear h-forward 



Write a fun tion to sear h for a regular expression that mat hes two or more blank lines in sequen e. Write a fun tion to sear h for dupli ated words, su h as `the the'. See se tion \Syntax of Regular Expressions" in The GNU Ema s Manual, for information on how to write a regexp (a regular expression) to mat h a string that is omposed of two identi al halves. You an devise several regexps; some are better than others. The fun tion I use is des ribed in an appendix, along with several regexps. See Appendix A, \the-the Dupli ated Words Fun tion", page 241.

The ount-words-region Fun tion

167

13 Counting: Repetition and Regexps Repetition and regular expression sear hes are powerful tools that you often use when you write ode in Ema s Lisp. This hapter illustrates the use of regular expression sear hes through the onstru tion of word ount

ommands using while loops and re ursion. The standard Ema s distribution ontains a fun tion for ounting the number of lines within a region. However, there is no orresponding fun tion for ounting words. Certain types of writing ask you to ount words. Thus, if you write an essay, you may be limited to 800 words; if you write a novel, you may dis ipline yourself to write 1000 words a day. It seems odd to me that Ema s la ks a word ount ommand. Perhaps people use Ema s mostly for

ode or types of do umentation that do not require word ounts; or perhaps they restri t themselves to the operating system word ount ommand, w . Alternatively, people may follow the publishers' onvention and ompute a word ount by dividing the number of hara ters in a do ument by ve. In any event, here are ommands to ount words.

13.1 The ount-words-region Fun tion A word ount ommand ould ount words in a line, paragraph, region, or bu er. What should the ommand over? You ould design the ommand to ount the number of words in a omplete bu er. However, the Ema s tradition en ourages exibility|you may want to ount words in just a se tion, rather than all of a bu er. So it makes more sense to design the ommand to ount the number of words in a region. On e you have a ount-wordsregion ommand, you an, if you wish, ount words in a whole bu er by marking it with C-x h (mark-whole-buffer). Clearly, ounting words is a repetitive a t: starting from the beginning of the region, you ount the rst word, then the se ond word, then the third word, and so on, until you rea h the end of the region. This means that word ounting is ideally suited to re ursion or to a while loop. First, we will implement the word ount ommand with a while loop, then with re ursion. The ommand will, of ourse, be intera tive. The template for an intera tive fun tion de nition is, as always: (defun name-of-fun tion (argument-list) "do umentation..." (intera tive-expression...) body ...)

What we need to do is ll in the slots. The name of the fun tion should be self-explanatory and similar to the existing ount-lines-region name. This makes the name easier to remember. ount-words-region is a good hoi e.

168

Chapter 13: Counting: Repetition and Regexps

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 senten 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 forward 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 following 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 ;;; 3. Send a message to the user. ( ond ((zerop ount) (message "The region does NOT have any words.")) ((= 1 ount) (message "The region has 1 word.")) (t (message "The region has %d words." ount))))))

As written, the fun tion works, but not in all ir umstan es.

13.1.1 The Whitespa e Bug in ount-words-region The ount-words-region ommand des ribed in the pre eding se tion has two bugs, or rather, one bug with two manifestations. First, if you mark a region ontaining only whitespa e in the middle of some text, the

ount-words-region ommand tells you that the region ontains one word! Se ond, if you mark a region ontaining only whitespa e at the end of the bu er or the a

essible portion of a narrowed bu er, the ommand displays an error message that looks like this: Sear h failed: "\\w+\\W*"

If you are reading this in Info in GNU Ema s, you an test for these bugs yourself. First, evaluate the fun tion in the usual manner to install it. If you wish, you an also install this keybinding by evaluating it: (global-set-key "\C- =" ' ount-words-region)

To ondu t the rst test, set mark and point to the beginning and end of the following line and then type C- = (or M-x ount-words-region if you have not bound C- =): one

two

three

Ema s will tell you, orre tly, that the region has three words. Repeat the test, but pla e mark at the beginning of the line and pla e point just before the word `one'. Again type the ommand C- = (or M-x

ount-words-region). Ema s should tell you that the region has no words, sin e it is omposed only of the whitespa e at the beginning of the line. But instead Ema s tells you that the region has one word! For the third test, opy the sample line to the end of the `*s rat h*' bu er and then type several spa es at the end of the line. Pla e mark right after the word `three' and point at the end of line. (The end of the line will be the end of the bu er.) Type C- = (or M-x ount-words-region) as you did before. Again, Ema s should tell you that the region has no words,

The Whitespa e Bug in ount-words-region

171

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 nition 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

The solution to this problem is to provide re-sear h-forward with a third argument of t, whi h auses the fun tion to return nil rather than signal an error if the sear h fails. However, if you make this hange and try it, you will see the message \Counting words in region ... " and . . . you will keep on seeing that message . . . , until you type C-g (keyboard-quit). Here is what happens: the sear h is limited to the region, as before, and it fails be ause there are no word- onstituent hara ters in the region, as expe ted. Consequently, the re-sear h-forward expression returns nil. It does nothing else. In parti ular, it does not move point, whi h it does as a side e e t if it nds the sear h target. After the re-sear h-forward expression returns nil, the next expression in the while loop is evaluated. This expression in rements the ount. Then the loop repeats. The true-orfalse-test tests true be ause the value of point is still less than the value of end, sin e the re-sear h-forward expression did not move point. . . . and the y le repeats . . . The ount-words-region de nition requires yet another modi ation, to ause the true-or-false-test of the while loop to test false if the sear h fails. Put another way, there are two onditions that must be satis ed in the true-or-false-test before the word ount variable is in remented: point must still be within the region and the sear h expression must have found a word to ount. Sin e both the rst ondition and the se ond ondition must be true together, the two expressions, the region test and the sear h expression, an be joined with an and spe ial form and embedded in the while loop as the true-or-false-test, like this: (and (< (point) end) (re-sear h-forward "\\w+\\W*" end t))

(For information about and, see Se tion 12.4, \forward-paragraph: a Goldmine of Fun tions", page 155.) The re-sear h-forward expression returns t if the sear h su

eeds and as a side e e t moves point. Consequently, as words are found, point is moved through the region. When the sear h expression fails to nd another word, or when point rea hes the end of the region, the true-or-false-test tests false, the while loop exists, and the ount-words-region fun tion displays one or other of its messages. After in orporating these nal hanges, the ount-words-region works without bugs (or at least, without bugs that I have found!). Here is what it looks like: ;;; Final version: while (defun ount-words-region (beginning end) "Print number of words in the region." (intera tive "r") (message "Counting words in region ... ")

Count Words Re ursively

173

;;; 1. Set up appropriate onditions. (save-ex ursion (let (( ount 0)) (goto- har beginning) ;;; 2. Run the while loop. (while (and (< (point) end) (re-sear h-forward "\\w+\\W*" end t)) (setq ount (1+ ount))) ;;; 3. Send a message to the user. ( ond ((zerop ount) (message "The region does NOT have any words.")) ((= 1 ount) (message "The region has 1 word.")) (t (message "The region has %d words." ount))))))

13.2 Count Words Re ursively You an write the fun tion for ounting words re ursively as well as with a while loop. Let's see how this is done. First, we need to re ognize that the ount-words-region fun tion has three jobs: it sets up the appropriate onditions for ounting to o

ur; it

ounts the words in the region; and it sends a message to the user telling how many words there are. If we write a single re ursive fun tion to do everything, we will re eive a message for every re ursive all. If the region ontains 13 words, we will re eive thirteen messages, one right after the other. We don't want this! Instead, we must write two fun tions to do the job, one of whi h (the re ursive fun tion) will be used inside of the other. One fun tion will set up the

onditions and display the message; the other will return the word ount. Let us start with the fun tion that auses the message to be displayed. We an ontinue to all this ount-words-region. This is the fun tion that the user will all. It will be intera tive. Indeed, it will be similar to our previous versions of this fun tion, ex ept that it will all re ursive- ount-words to determine how many words are in the region.

174

Chapter 13: Counting: Repetition and Regexps

We an readily onstru t a template for this fun tion, based on our previous versions: ;; Re ursive version; uses regular expression sear h (defun ount-words-region (beginning end) "do umentation..." (intera tive-expression...) ;;; 1. Set up appropriate onditions. (explanatory message ) (set-up fun tions ... ;;; 2. Count the words.

re ursive all

;;; 3. Send a message to the user. message providing word ount))

The de nition looks straightforward, ex ept that somehow the ount returned 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. Often, one thinks of the binding within a let expression as somehow se ondary to the `primary' work of a fun tion. But in this ase, what you might onsider the `primary' job of the fun tion, ounting words, is done within the let expression. Using let, the fun tion de nition looks like this: (defun ount-words-region (beginning end) "Print number of words in the region." (intera tive "r") ;;; 1. Set up appropriate onditions. (message "Counting words in region ... ") (save-ex ursion (goto- har beginning) ;;; 2. Count the words. (let (( ount (re ursive- ount-words end)))

Count Words Re ursively

175

;;; 3. Send a message to the user. ( ond ((zerop ount) (message "The region does NOT have any words.")) ((= 1 ount) (message "The region has 1 word.")) (t (message "The region has %d words." ount))))))

Next, we need to write the re ursive ounting fun tion. A re ursive fun tion has at least three parts: the `do-again-test', the `next-step-expression', and the re ursive all. The do-again-test determines whether the fun tion will or will not be

alled again. Sin e we are ounting words in a region and an use a fun tion that moves point forward for every word, the do-again-test an he k whether point is still within the region. The do-again-test should nd the value of point and determine whether point is before, at, or after the value of the end of the region. We an use the point fun tion to lo ate point. Clearly, we must pass the value of the end of the region to the re ursive ounting fun tion as an argument. In addition, the do-again-test should also test whether the sear h nds a word. If it does not, the fun tion should not all itself again. The next-step-expression hanges a value so that when the re ursive fun tion is supposed to stop alling itself, it stops. More pre isely, the next-stepexpression hanges a value so that at the right time, the do-again-test stops the re ursive fun tion from alling itself again. In this ase, the next-stepexpression an be the expression that moves point forward, word by word. The third part of a re ursive fun tion is the re ursive all. Somewhere, also, we also need a part that does the `work' of the fun tion, a part that does the ounting. A vital part! But already, we have an outline of the re ursive ounting fun tion: (defun re ursive- ount-words (region-end) "do umentation..."

do-again-test next-step-expression re ursive all )

Now we need to ll in the slots. Let's start with the simplest ases rst: if point is at or beyond the end of the region, there annot be any words in the region, so the fun tion should return zero. Likewise, if the sear h fails, there are no words to ount, so the fun tion should return zero. On the other hand, if point is within the region and the sear h su

eeds, the fun tion should all itself again.

176

Chapter 13: Counting: Repetition and Regexps

Thus, the do-again-test should look like this: (and (< (point) region-end) (re-sear h-forward "\\w+\\W*" region-end t))

Note that the sear h expression is part of the do-again-test|the fun tion returns t if its sear h su

eeds and nil if it fails. (See Se tion 13.1.1, \The Whitespa e Bug in ount-words-region", page 170, for an explanation of how re-sear h-forward works.) The do-again-test is the true-or-false test of an if lause. Clearly, if the do-again-test su

eeds, the then-part of the if lause should all the fun tion again; but if it fails, the else-part should return zero sin e either point is outside the region or the sear h failed be ause there were no words to nd. But before onsidering the re ursive all, we need to onsider the nextstep-expression. What is it? Interestingly, it is the sear h part of the doagain-test. In addition to returning t or nil for the do-again-test, re-sear hforward moves point forward as a side e e t of a su

essful sear h. This is the a tion that hanges the value of point so that the re ursive fun tion stops

alling itself when point ompletes its movement through the region. Consequently, the re-sear h-forward expression is the next-step-expression. In outline, then, the body of the re ursive- ount-words fun tion looks like this: (if do-again-test-and-next-step- ombined ;; then

re ursive- all-returning- ount

;; else

return-zero )

How to in orporate the me hanism that ounts? If you are not used to writing re ursive fun tions, a question like this an be troublesome. But it an and should be approa hed systemati ally. We know that the ounting me hanism should be asso iated in some way with the re ursive all. Indeed, sin e the next-step-expression moves point forward by one word, and sin e a re ursive all is made for ea h word, the ounting me hanism must be an expression that adds one to the value returned by a all to re ursive- ount-words. Consider several ases:  If there are two words in the region, the fun tion should return a value resulting from adding one to the value returned when it ounts the rst word, plus the number returned when it ounts the remaining words in the region, whi h in this ase is one.  If there is one word in the region, the fun tion should return a value resulting from adding one to the value returned when it ounts that

Count Words Re ursively

177

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: The re ursive fun tion: (defun re ursive- ount-words (region-end) "Number of words between point and REGION-END." ;;; 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))

The wrapper: ;;; Re ursive version (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 ... ") (save-ex ursion (goto- har beginning) (let (( ount (re ursive- ount-words end))) ( ond ((zerop ount) (message "The region does NOT have any words.")) ((= 1 ount) (message "The region has 1 word.")) (t (message "The region has %d words." ount))))))

Exer ise: Counting Pun tuation

179

13.3 Exer ise: Counting Pun tuation Using a while loop, write a fun tion to ount the number of pun tuation marks in a region|period, omma, semi olon, olon, ex lamation mark, and question mark. Do the same using re ursion.

180

Chapter 13: Counting: Repetition and Regexps

What to Count?

181

14 Counting Words in a defun Our next proje t is to ount the number of words in a fun tion de nition. Clearly, this an be done using some variant of ount-word-region. See Chapter 13, \Counting Words: Repetition and Regexps", page 167. If we are just going to ount the words in one de nition, it is easy enough to mark the de nition with the C-M-h (mark-defun) ommand, and then all

ount-word-region. However, I am more ambitious: I want to ount the words and symbols in every de nition in the Ema s sour es and then print a graph that shows how many fun tions there are of ea h length: how many ontain 40 to 49 words or symbols, how many ontain 50 to 59 words or symbols, and so on. I have often been urious how long a typi al fun tion is, and this will tell. Des ribed in one phrase, the histogram proje t is daunting; but divided into numerous small steps, ea h of whi h we an take one at a time, the proje t be omes less fearsome. Let us onsider what the steps must be:  First, write a fun tion to ount the words in one de nition. This in ludes the problem of handling symbols as well as words.  Se ond, write a fun tion to list the numbers of words in ea h fun tion in a le. This fun tion an use the ount-words-in-defun fun tion.  Third, write a fun tion to list the numbers of words in ea h fun tion in ea h of several les. This entails automati ally nding the various les, swit hing to them, and ounting the words in the de nitions within them.  Fourth, write a fun tion to onvert the list of numbers that we reated in step three to a form that will be suitable for printing as a graph.  Fifth, write a fun tion to print the results as a graph. This is quite a proje t! But if we take ea h step slowly, it will not be diÆ ult.

14.1 What to Count? When we rst start thinking about how to ount the words in a fun tion de nition, the rst question is (or ought to be) what are we going to ount? When we speak of `words' with respe t to a Lisp fun tion de nition, we are a tually speaking, in large part, of `symbols'. For example, the following multiply-by-seven fun tion ontains the ve symbols defun, multiplyby-seven, number, *, and 7. In addition, in the do umentation string, it

ontains the four words `Multiply', `NUMBER', `by', and `seven'. The symbol `number' is repeated, so the de nition ontains a total of ten words and symbols. (defun multiply-by-seven (number) "Multiply NUMBER by seven." (* 7 number))

182

Chapter 14: Counting Words in a defun

However, if we mark the multiply-by-seven de nition with C-M-h (markdefun), and then all ount-words-region on it, we will nd that ountwords-region laims the de nition has eleven words, not ten! Something is wrong! The problem is twofold: ount-words-region does not ount the `*' as a word, and it ounts the single symbol, multiply-by-seven, as ontaining three words. The hyphens are treated as if they were interword spa es rather than intraword onne tors: `multiply-by-seven' is ounted as if it were written `multiply by seven'. The ause of this onfusion is the regular expression sear h within the

ount-words-region de nition that moves point forward word by word. In the anoni al version of ount-words-region, the regexp is: "\\w+\\W*"

This regular expression is a pattern de ning one or more word onstituent

hara ters possibly followed by one or more hara ters that are not word

onstituents. What is meant by `word onstituent hara ters' brings us to the issue of syntax, whi h is worth a se tion of its own.

14.2 What Constitutes a Word or Symbol? Ema s treats di erent hara ters as belonging to di erent syntax ategories. For example, the regular expression, `\\w+', is a pattern spe ifying one or more word onstituent hara ters. Word onstituent hara ters are members of one syntax ategory. Other syntax ategories in lude the lass of pun tuation hara ters, su h as the period and the omma, and the lass of whitespa e hara ters, su h as the blank spa e and the tab hara ter. (For more information, see se tion \The Syntax Table" in The GNU Ema s Manual, and se tion \Syntax Tables" in The GNU Ema s Lisp Referen e Manual.) Syntax tables spe ify whi h hara ters belong to whi h ategories. Usually, a hyphen is not spe i ed as a `word onstituent hara ter'. Instead, it is spe i ed as being in the ` lass of hara ters that are part of symbol names but not words.' This means that the ount-words-region fun tion treats it in the same way it treats an interword white spa e, whi h is why

ount-words-region ounts `multiply-by-seven' as three words. There are two ways to ause Ema s to ount `multiply-by-seven' as one symbol: modify the syntax table or modify the regular expression. We ould rede ne a hyphen as a word onstituent hara ter by modifying the syntax table that Ema s keeps for ea h mode. This a tion would serve our purpose, ex ept that a hyphen is merely the most ommon hara ter within symbols that is not typi ally a word onstituent hara ter; there are others, too.

The ount-words-in-defun Fun tion

183

Alternatively, we an rede ne the regular expression used in the ountwords de nition so as to in lude symbols. This pro edure has the merit of

larity, but the task is a little tri ky. The rst part is simple enough: the pattern must mat h \at least one

hara ter that is a word or symbol onstituent". Thus: "\\(\\w\\|\\s_\\)+"

The `\\(' is the rst part of the grouping onstru t that in ludes the `\\w' and the `\\s_' as alternatives, separated by the `\\|'. The `\\w' mat hes any word- onstituent hara ter and the `\\s_' mat hes any hara ter that is part of a symbol name but not a word- onstituent hara ter. The `+' following the group indi ates that the word or symbol onstituent hara ters must be mat hed at least on e. However, the se ond part of the regexp is more diÆ ult to design. What we want is to follow the rst part with \optionally one or more hara ters that are not onstituents of a word or symbol". At rst, I thought I ould de ne this with the following: "\\(\\W\\|\\S_\\)*"

The upper ase `W' and `S' mat h hara ters that are not word or symbol

onstituents. Unfortunately, this expression mat hes any hara ter that is either not a word onstituent or not a symbol onstituent. This mat hes any

hara ter! I then noti ed that every word or symbol in my test region was followed by white spa e (blank spa e, tab, or newline). So I tried pla ing a pattern to mat h one or more blank spa es after the pattern for one or more word or symbol onstituents. This failed, too. Words and symbols are often separated by whitespa e, but in a tual ode parentheses may follow symbols and pun tuation may follow words. So nally, I designed a pattern in whi h the word or symbol onstituents are followed optionally by hara ters that are not white spa e and then followed optionally by white spa e. Here is the full regular expression: "\\(\\w\\|\\s_\\)+[^ \t\nâ„„*[ \t\nâ„„*"

14.3 The ount-words-in-defun Fun tion We have seen that there are several ways to write a ount-word-region fun tion. To write a ount-words-in-defun, we need merely adapt one of these versions. The version that uses a while loop is easy to understand, so I am going to adapt that. Be ause ount-words-in-defun will be part of a more omplex program, it need not be intera tive and it need not display a message but just return the ount. These onsiderations simplify the de nition a little. On the other hand, ount-words-in-defun will be used within a bu er that ontains fun tion de nitions. Consequently, it is reasonable to ask that

184

Chapter 14: Counting Words in a defun

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 ontaining 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 beginning 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 expression, 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-indefun 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.

14.4 Count Several defuns Within a File A le su h as `simple.el' may have 80 or more fun tion de nitions within it. Our long term goal is to olle t statisti s on many les, but as a rst step, our immediate goal is to olle t statisti s on one le. The information will be a series of numbers, ea h number being the length of a fun tion de nition. We an store the numbers in a list. We know that we will want to in orporate the information regarding one le with information about many other les; this means that the fun tion for ounting de nition lengths within one le need only return the list of lengths. It need not and should not display any messages. The word ount ommands ontain one expression to jump point forward word by word and another expression to ount the jumps. The fun tion to return the lengths of de nitions an be designed to work the same way, with one expression to jump point forward de nition by de nition and another expression to onstru t the lengths' list. This statement of the problem makes it elementary to write the fun tion de nition. Clearly, we will start the ount at the beginning of the le, so the rst ommand will be (goto- har (point-min)). Next, we start the while loop; and the true-or-false test of the loop an be a regular expression sear h for the next fun tion de nition|so long as the sear h su

eeds, point is moved forward and then the body of the loop is evaluated. The body needs an expression that onstru ts the lengths' list. ons, the list onstru tion

ommand, an be used to reate the list. That is almost all there is to it.

lengths-list-file in Detail

187

Here is what this fragment of ode looks like: (goto- har (point-min)) (while (re-sear h-forward "^(defun" nil t) (setq lengths-list ( ons ( ount-words-in-defun) lengths-list)))

What we have left out is the me hanism for nding the le that ontains the fun tion de nitions. In previous examples, we either used this, the Info le, or we swit hed ba k and forth to some other bu er, su h as the `*s rat h*' bu er. Finding a le is a new pro ess that we have not yet dis ussed.

14.5 Find a File To nd a le in Ema s, you use the C-x C-f (find-file) ommand. This

ommand is almost, but not quite right for the lengths problem. Let's look at the sour e for find-file (you an use the find-tag ommand or C-h f (des ribe-fun tion) to nd the sour e of a fun tion): (defun find-file (filename) "Edit file FILENAME. Swit h to a buffer visiting file FILENAME,

reating one if none already exists." (intera tive "FFind file: ") (swit h-to-buffer (find-file-nosele t filename)))

The de nition possesses short but omplete do umentation and an intera tive spe i ation that prompts you for a le name when you use the

ommand intera tively. The body of the de nition ontains two fun tions, find-file-nosele t and swit h-to-buffer. A

ording to its do umentation as shown by C-h f (the des ribefun tion ommand), the find-file-nosele t fun tion reads the named le into a bu er and returns the bu er. However, the bu er is not sele ted. Ema s does not swit h its attention (or yours if you are using find-filenosele t) to the named bu er. That is what swit h-to-buffer does: it swit hes the bu er to whi h Ema s attention is dire ted; and it swit hes the bu er displayed in the window to the new bu er. We have dis ussed bu er swit hing elsewhere. (See Se tion 2.3, \Swit hing Bu ers", page 26.) In this histogram proje t, we do not need to display ea h le on the s reen as the program determines the length of ea h de nition within it. Instead of employing swit h-to-buffer, we an work with set-buffer, whi h redire ts the attention of the omputer program to a di erent bu er but does not redisplay it on the s reen. So instead of alling on find-file to do the job, we must write our own expression. The task is easy: use find-file-nosele t and set-buffer.

188

Chapter 14: Counting Words in a defun

14.6

lengths-list-file

in Detail

The ore of the lengths-list-file fun tion is a while loop ontaining a fun tion to move point forward `defun by defun' and a fun tion to ount the number of words and symbols in ea h defun. This ore must be surrounded by fun tions that do various other tasks, in luding nding the le, and ensuring that point starts out at the beginning of the le. The fun tion de nition looks like this: (defun lengths-list-file (filename) "Return list of definitions' lengths within FILE. The returned list is a list of numbers. Ea h number is the number of words or symbols in one fun tion definition." (message "Working on `%s' ... " filename) (save-ex ursion (let ((buffer (find-file-nosele t filename)) (lengths-list)) (set-buffer buffer) (setq buffer-read-only t) (widen) (goto- har (point-min)) (while (re-sear h-forward "^(defun" nil t) (setq lengths-list ( ons ( ount-words-in-defun) lengths-list))) (kill-buffer buffer) lengths-list)))

The fun tion is passed one argument, the name of the le on whi h it will work. It has four lines of do umentation, but no intera tive spe i ation. Sin e people worry that a omputer is broken if they don't see anything going on, the rst line of the body is a message. The next line ontains a save-ex ursion that returns Ema s' attention to the urrent bu er when the fun tion ompletes. This is useful in ase you embed this fun tion in another fun tion that presumes point is restored to the original bu er. In the varlist of the let expression, Ema s nds the le and binds the lo al variable buffer to the bu er ontaining the le. At the same time, Ema s reates lengths-list as a lo al variable. Next, Ema s swit hes its attention to the bu er. In the following line, Ema s makes the bu er read-only. Ideally, this line is not ne essary. None of the fun tions for ounting words and symbols in a fun tion de nition should hange the bu er. Besides, the bu er is not going to be saved, even if it were hanged. This line is entirely the onsequen e of great, perhaps ex essive, aution. The reason for the aution is that this fun tion and those it alls work on the sour es for Ema s and it is very

lengths-list-file in Detail

189

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-lastsexp). (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.

14.7 Count Words in defuns in Di erent Files In the previous se tion, we reated a fun tion that returns a list of the lengths of ea h de nition in a le. Now, we want to de ne a fun tion to return a master list of the lengths of the de nitions in a list of les. Working on ea h of a list of les is a repetitious a t, so we an use either a while loop or re ursion. The design using a while loop is routine. The argument passed the fun tion is a list of les. As we saw earlier (see Se tion 11.1.1, \Loop Example", page 122), you an write a while loop so that the body of the loop is evaluated if su h a list ontains elements, but to exit the loop if the list is empty. For this design to work, the body of the loop must ontain an expression that shortens the list ea h time the body is evaluated, so that eventually the list is empty. The usual te hnique is to set the value of the list to the value of the dr of the list ea h time the body is evaluated. The template looks like this: (while test-whether-list-is-empty body ... set-list-to- dr-of-list)

Also, we remember that a while loop returns nil (the result of evaluating the true-or-false-test), not the result of any evaluation within its body. (The evaluations within the body of the loop are done for their side e e ts.) However, the expression that sets the lengths' list is part of the body|and that is the value that we want returned by the fun tion as a whole. To do this, we en lose the while loop within a let expression, and arrange that the last element of the let expression ontains the value of the lengths' list. (See \Loop Example with an In rementing Counter", page 125.)

The append Fun tion

191

These onsiderations lead us dire tly to the fun tion itself: ;;; Use while loop. (defun lengths-list-many-files (list-of-files) "Return list of lengths of defuns in LIST-OF-FILES." (let (lengths-list) ;;; true-or-false-test (while list-of-files (setq lengths-list (append lengths-list ;;; Generate a lengths' list. (lengths-list-file (expand-file-name ( ar list-of-files))))) ;;; Make les' list shorter. (setq list-of-files ( dr list-of-files))) ;;; Return nal value of lengths' list. lengths-list))

expand-file-name is a built-in fun tion that onverts a le name to the absolute, long, path name form of the dire tory in whi h the fun tion is

alled. Thus, if expand-file-name is alled on debug.el when Ema s is visiting the `/usr/lo al/share/ema s/21.0.100/lisp/ema s-lisp/' dire tory, debug.el

be omes /usr/lo al/share/ema s/21.0.100/lisp/ema s-lisp/debug.el

The only other new element of this fun tion de nition is the as yet unstudied fun tion append, whi h merits a short se tion for itself.

14.7.1 The append Fun tion The append fun tion atta hes one list to another. Thus, (append '(1 2 3 4) '(5 6 7 8))

produ es the list (1 2 3 4 5 6 7 8)

This is exa tly how we want to atta h two lengths' lists produ ed by

lengths-list-file to ea h other. The results ontrast with ons, ( ons '(1 2 3 4) '(5 6 7 8))

192

Chapter 14: Counting Words in a defun

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)

14.8 Re ursively Count Words in Di erent Files Besides a while loop, you an work on ea h of a list of les with re ursion. A re ursive version of lengths-list-many-files is short and simple. The re ursive fun tion has the usual parts: the `do-again-test', the `nextstep-expression', and the re ursive all. The `do-again-test' determines whether the fun tion should all itself again, whi h it will do if the listof-files ontains any remaining elements; the `next-step-expression' resets the list-of-files to the dr of itself, so eventually the list will be empty; and the re ursive all alls itself on the shorter list. The omplete fun tion is shorter than this des ription! (defun re ursive-lengths-list-many-files (list-of-files) "Return list of lengths of ea h defun in LIST-OF-FILES." (if list-of-files ; do-again-test (append (lengths-list-file (expand-file-name ( ar list-of-files))) (re ursive-lengths-list-many-files ( dr list-of-files)))))

In a senten e, the fun tion returns the lengths' list for the rst of the listof-files appended to the result of alling itself on the rest of the listof-files. Here is a test of re ursive-lengths-list-many-files, along with the results of running lengths-list-file on ea h of the les individually. Install re ursive-lengths-list-many-files and lengths-list-file, if ne essary, and then evaluate the following expressions. You may need to

hange the les' pathnames; those here work when this Info le and the Ema s sour es are lo ated in their ustomary pla es. To hange the expressions, opy them to the `*s rat h*' bu er, edit them, and then evaluate them. The results are shown after the `)'. (These results are for les from Ema s Version 21.0.100; les from other versions of Ema s may produ e di erent results.) ( d "/usr/lo al/share/ema s/21.0.100/") (lengths-list-file "./lisp/ma ros.el") ) (273 263 456 90) (lengths-list-file "./lisp/mail/mailalias.el") ) (38 32 26 77 174 180 321 198 324)

Sorting Lists

193

(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 output we want. The next step is to prepare the data in the list for display in a graph.

14.9 Prepare the Data for Display in a Graph The re ursive-lengths-list-many-files fun tion returns a list of numbers. Ea h number re ords the length of a fun tion de nition. What we need to do now is transform this data into a list of numbers suitable for generating a graph. The new list will tell how many fun tions de nitions

ontain less than 10 words and symbols, how many ontain between 10 and 19 words and symbols, how many ontain between 20 and 29 words and symbols, and so on. In brief, we need to go through the lengths' list produ ed by the re ursive-lengths-list-many-files fun tion and ount the number of defuns within ea h range of lengths, and produ e a list of those numbers. Based on what we have done before, we an readily foresee that it should not be too hard to write a fun tion that ` drs' down the lengths' list, looks at ea h element, determines whi h length range it is in, and in rements a

ounter for that range. However, before beginning to write su h a fun tion, we should onsider the advantages of sorting the lengths' list rst, so the numbers are ordered from smallest to largest. First, sorting will make it easier to ount the numbers in ea h range, sin e two adja ent numbers will either be in the same length range or in adja ent ranges. Se ond, by inspe ting a sorted list, we an dis over the highest and lowest number, and thereby determine the largest and smallest length range that we will need.

14.9.1 Sorting Lists Ema s ontains a fun tion to sort lists, alled (as you might guess) sort. The sort fun tion takes two arguments, the list to be sorted, and a predi ate that determines whether the rst of two list elements is \less" than the se ond. As we saw earlier (see Se tion 1.8.4, \Using the Wrong Type Obje t as an Argument", page 14), a predi ate is a fun tion that determines whether

194

Chapter 14: Counting Words in a defun

some property is true or false. The sort fun tion will reorder a list a

ording 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.)

14.9.2 Making a List of Files The re ursive-lengths-list-many-files fun tion requires a list of les as its argument. For our test examples, we onstru ted su h a list by hand; but the Ema s Lisp sour e dire tory is too large for us to do for that. Instead, we will write a fun tion to do the job for us. In this fun tion, we will use both a while loop and a re ursive all. We did not have to write a fun tion like this for older versions of GNU Ema s, sin e they pla ed all the `.el' les in one dire tory. Instead, we were able to use the dire tory-files fun tion, whi h lists the names of les that mat h a spe i ed pattern within a single dire tory. However, re ent versions of Ema s pla e Ema s Lisp les in subdire tories of the top level `lisp' dire tory. This re-arrangement eases navigation. For example, all the mail related les are in a `lisp' sub-dire tory alled `mail'. But at the same time, this arrangement for es us to reate a le listing fun tion that des ends into the sub-dire tories. We an reate this fun tion, alled files-in-below-dire tory, using familiar fun tions su h as ar, nth dr, and substring in onjun tion with an existing fun tion alled dire tory-files-and-attributes. This latter

Making a List of Files

195

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 different 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-belowdire 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)

14.9.3 Counting fun tion de nitions Our immediate goal is to generate a list that tells us how many fun tion de nitions ontain fewer than 10 words and symbols, how many ontain

198

Chapter 14: Counting Words in a defun

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'.")

To hange the ranges, we edit this list. Next, we need to write the fun tion that reates the list of the number of de nitions within ea h range. Clearly, this fun tion must take the sortedlengths and the top-of-ranges lists as arguments. The defuns-per-range fun tion must do two things again and again: it must ount the number of de nitions within a range spe i ed by the urrent top-of-range value; and it must shift to the next higher value in the topof-ranges list after ounting the number of de nitions in the urrent range. Sin e ea h of these a tions is repetitive, we an use while loops for the job. One loop ounts the number of de nitions in the range de ned by the urrent top-of-range value, and the other loop sele ts ea h of the top-of-range values in turn. Several entries of the sorted-lengths list are ounted for ea h range; this means that the loop for the sorted-lengths list will be inside the loop for the top-of-ranges list, like a small gear inside a big gear. The inner loop ounts the number of de nitions within the range. It is a simple ounting loop of the type we have seen before. (See Se tion 11.1.3, \A loop with an in rementing ounter", page 124.) The true-or-false test of the loop tests whether the value from the sorted-lengths list is smaller than the urrent value of the top of the range. If it is, the fun tion in rements the ounter and tests the next value from the sorted-lengths list.

Counting fun tion de nitions

199

The inner loop looks like this: (while length-element-smaller-than-top-of-range (setq number-within-range (1+ number-within-range)) (setq sorted-lengths ( dr sorted-lengths)))

The outer loop must start with the lowest value of the top-of-ranges list, and then be set to ea h of the su

eeding higher values in turn. This

an be done with a loop like this: (while top-of-ranges body-of-loop... (setq top-of-ranges ( dr top-of-ranges)))

Put together, the two loops look like this: (while top-of-ranges ;; Count the number of elements within the urrent range. (while length-element-smaller-than-top-of-range (setq number-within-range (1+ number-within-range)) (setq sorted-lengths ( dr sorted-lengths))) ;; Move to next range. (setq top-of-ranges ( dr top-of-ranges)))

In addition, in ea h ir uit of the outer loop, Ema s should re ord the number of de nitions within that range (the value of number-within-range) in a list. We an use ons for this purpose. (See Se tion 7.2, \ ons", page 83.) The ons fun tion works ne, ex ept that the list it onstru ts will ontain the number of de nitions for the highest range at its beginning and the number of de nitions for the lowest range at its end. This is be ause ons atta hes new elements of the list to the beginning of the list, and sin e the two loops are working their way through the lengths' list from the lower end rst, the defuns-per-range-list will end up largest number rst. But we will want to print our graph with smallest values rst and the larger later. The solution is to reverse the order of the defuns-per-range-list. We an do this using the nreverse fun tion, whi h reverses the order of a list. For example, (nreverse '(1 2 3 4))

produ es:

(4 3 2 1)

Note that the nreverse fun tion is \destru tive"|that is, it hanges the list to whi h it is applied; this ontrasts with the ar and dr fun tions, whi h are non-destru tive. In this ase, we do not want the original defunsper-range-list, so it does not matter that it is destroyed. (The reverse fun tion provides a reversed opy of a list, leaving the original list as is.)

200

Chapter 14: Counting Words in a defun

Put all together, the defuns-per-range looks like this: (defun defuns-per-range (sorted-lengths top-of-ranges) "SORTED-LENGTHS defuns in ea h TOP-OF-RANGES range." (let ((top-of-range ( ar top-of-ranges)) (number-within-range 0) defuns-per-range-list) ;; Outer loop. (while top-of-ranges ;; Inner loop. (while (and ;; Need number for numeri test. ( ar sorted-lengths) (< ( ar sorted-lengths) top-of-range)) ;; Count number of de nitions within urrent range. (setq number-within-range (1+ number-within-range)) (setq sorted-lengths ( dr sorted-lengths))) ;; Exit inner loop but remain within outer loop. (setq defuns-per-range-list ( ons number-within-range defuns-per-range-list)) (setq number-within-range 0) ; Reset ount to zero. ;; Move to next range. (setq top-of-ranges ( dr top-of-ranges)) ;; Spe ify next top of range value. (setq top-of-range ( ar top-of-ranges))) ;; Exit outer loop and ount the number of defuns larger than ;; the largest top-of-range value. (setq defuns-per-range-list ( ons (length sorted-lengths) defuns-per-range-list)) ;; Return a list of the number of de nitions within ea h range, ;; smallest to largest. (nreverse defuns-per-range-list)))

Counting fun tion de nitions

201

The fun tion is straightforward ex ept for one subtle feature. The true-orfalse test of the inner loop looks like this: (and ( ar sorted-lengths) (< ( ar sorted-lengths) top-of-range))

instead of like this: (< ( 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-perrange 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) expression 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)) (defuns-per-range sorted-lengths top-of-ranges)

202

Chapter 14: Counting Words in a defun

The list returned looks like this: (2 2 2 0 0 1 0 2 0 0 4)

Indeed, there are two elements of the sorted-lengths list smaller than 110, two elements between 110 and 119, two elements between 120 and 129, and so on. There are four elements with a value of 200 or larger.

Readying a Graph

203

15 Readying a Graph Our goal is to onstru t a graph showing the numbers of fun tion de nitions 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 graphprinting 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 olumninsertion 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 ommand. 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

Indeed, this is the fun tion we want; its do umentation says: insert-re tangle: Insert text of RECTANGLE with upper left orner at point. RECTANGLE's first line is inserted at point, its se ond line is inserted at a point verti ally under point, et . RECTANGLE should be a list of strings.

We an run a qui k test, to make sure it does what we expe t of it. Here is the result of pla ing the ursor after the insert-re tangle expression and typing C-u C-x C-e (eval-last-sexp). The fun tion inserts the strings `"first"', `"se ond"', and `"third"' at and below point. Also the fun tion returns nil. (insert-re tangle '("first" "se ond" "third"))first se ond third nil

Of ourse, we won't be inserting the text of the insert-re tangle expression itself into the bu er in whi h we are making the graph, but will all the fun tion from our program. We shall, however, have to make sure that point is in the bu er at the pla e where the insert-re tangle fun tion will insert its olumn of strings. If you are reading this in Info, you an see how this works by swit hing to another bu er, su h as the `*s rat h*' bu er, pla ing point somewhere in the bu er, typing M-:, typing the insert-re tangle expression into the minibu er at the prompt, and then typing hRETi. This auses Ema s to evaluate the expression in the minibu er, but to use as the value of point the position of point in the `*s rat h*' bu er. (M-: is the keybinding for eval-expression.) We nd when we do this that point ends up at the end of the last inserted line|that is to say, this fun tion moves point as a side-e e t. If we were to repeat the ommand, with point at this position, the next insertion would be below and to the right of the previous insertion. We don't want this! If we are going to make a bar graph, the olumns need to be beside ea h other. So we dis over that ea h y le of the olumn-inserting while loop must reposition point to the pla e we want it, and that pla e will be at the top, not the bottom, of the olumn. Moreover, we remember that when we print a graph, we do not expe t all the olumns to be the same height. This means that the top of ea h olumn may be at a di erent height from the previous one. We annot simply reposition point to the same line ea h time, but moved over to the right|or perhaps we an. . . We are planning to make the olumns of the bar graph out of asterisks. The number of asterisks in the olumn is the number spe i ed by the urrent element of the numbers-list. We need to onstru t a list of asterisks of the right length for ea h all to insert-re tangle. If this list onsists solely of the requisite number of asterisks, then we will have position point the right

Readying a Graph

205

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 insertre tangle must be blanks rather than asterisks. For example, if the maximum 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)

(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, 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 hforward 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

The se ond and subsequent arguments to apply are optional, so we an use apply to all a fun tion and pass the elements of a list to it, like this, whi h also returns 8: (apply 'max '(4 8 5))

This latter way is how we will use apply. The re ursive-lengthslist-many-files fun tion returns a numbers' list to whi h we an apply max (we ould also apply max to the sorted numbers' list; it does not matter

whether the list is sorted or not.) Hen e, the operation for nding the maximum height of the graph is this: (setq max-graph-height (apply 'max numbers-list))

Now we an return to the question of how to reate a list of strings for a

olumn of the graph. Told the maximum height of the graph and the number of asterisks that should appear in the olumn, the fun tion should return a list of strings for the insert-re tangle ommand to insert. Ea h olumn is made up of asterisks or blanks. Sin e the fun tion is passed the value of the height of the olumn and the number of asterisks in the olumn, the number of blanks an be found by subtra ting the number of asterisks from the height of the olumn. Given the number of blanks and the number of asterisks, two while loops an be used to onstru t the list: ;;; First version. (defun olumn-of-graph (max-graph-height a tual-height) "Return list of strings that is one olumn of a graph." (let ((insert-list nil) (number-of-top-blanks (- max-graph-height a tual-height))) ;; Fill in asterisks. (while (> a tual-height 0) (setq insert-list ( ons "*" insert-list)) (setq a tual-height (1- a tual-height))) ;; Fill in blanks. (while (> number-of-top-blanks 0) (setq insert-list ( ons " " insert-list)) (setq number-of-top-blanks (1- number-of-top-blanks))) ;; Return whole list. insert-list))

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 (" " " " "*" "*" "*")

As written, olumn-of-graph ontains a major aw: the symbols used for the blank and for the marked entries in the olumn are `hard- oded' as a spa e and asterisk. This is ne for a prototype, but you, or another user, may wish to use other symbols. For example, in testing the graph fun tion, you many want to use a period in pla e of the spa e, to make sure the point is being repositioned properly ea h time the insert-re tangle fun tion is

alled; or you might want to substitute a `+' sign or other symbol for the asterisk. You might even want to make a graph- olumn that is more than one display olumn wide. The program should be more exible. The way to do that is to repla e the blank and the asterisk with two variables that we an

all graph-blank and graph-symbol and de ne those variables separately. Also, the do umentation is not well written. These onsiderations lead us to the se ond version of the fun tion: (defvar graph-symbol "*" "String used as symbol in graph, usually an asterisk.") (defvar graph-blank " " "String used as blank in graph, usually a blank spa e. graph-blank must be the same number of olumns wide as graph-symbol.")

(For an explanation of defvar, see Se tion 8.4, \Initializing a Variable with

defvar", page 100.)

;;; Se ond version. (defun olumn-of-graph (max-graph-height a tual-height) "Return MAX-GRAPH-HEIGHT strings; ACTUAL-HEIGHT are graph-symbols. The graph-symbols are ontiguous entries at the end of the list. The list will be inserted as one olumn of a graph. The strings are either graph-blank or graph-symbol." (let ((insert-list nil) (number-of-top-blanks (- max-graph-height a tual-height))) ;; Fill in graph-symbols. (while (> a tual-height 0) (setq insert-list ( ons graph-symbol insert-list)) (setq a tual-height (1- a tual-height)))

208

Chapter 15: Readying a Graph ;; 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))) ;; Return whole list. insert-list))

If we wished, we ould rewrite olumn-of-graph a third time to provide optionally for a line graph as well as for a bar graph. This would not be hard to do. One way to think of a line graph is that it is no more than a bar graph in whi h the part of ea h bar that is below the top is blank. To

onstru t a olumn for a line graph, the fun tion rst onstru ts a list of blanks that is one shorter than the value, then it uses ons to atta h a graph symbol to the list; then it uses ons again to atta h the `top blanks' to the list. It is easy to see how to write su h a fun tion, but sin e we don't need it, we will not do it. But the job ould be done, and if it were done, it would be done with olumn-of-graph. Even more important, it is worth noting that few hanges would have to be made anywhere else. The enhan ement, if we ever wish to make it, is simple. Now, nally, we ome to our rst a tual graph printing fun tion. This prints the body of a graph, not the labels for the verti al and horizontal axes, so we an all this graph-body-print.

15.1 The graph-body-print Fun tion After our preparation in the pre eding se tion, the graph-body-print fun tion is straightforward. The fun tion will print olumn after olumn of asterisks and blanks, using the elements of a numbers' list to spe ify the number of asterisks in ea h olumn. This is a repetitive a t, whi h means we an use a de rementing while loop or re ursive fun tion for the job. In this se tion, we will write the de nition using a while loop. The olumn-of-graph fun tion requires the height of the graph as an argument, so we should determine and re ord that as a lo al variable. This leads us to the following template for the while loop version of this fun tion: (defun graph-body-print (numbers-list) "do umentation..." (let ((height ... ...)) (while numbers-list

insert- olumns-and-reposition-point

(setq numbers-list ( dr numbers-list)))))

The graph-body-print Fun tion

209

We need to ll in the slots of the template. Clearly, we an use the (apply 'max numbers-list) expression to determine the height of the graph. The while loop will y le through the numbers-list one element at a time. As it is shortened by the (setq numbers-list ( dr numbers-list)) expression, the ar of ea h instan e of the list is the value of the argument for olumn-of-graph. At ea h y le of the while loop, the insert-re tangle fun tion inserts the list returned by olumn-of-graph. Sin e the insert-re tangle fun tion moves point to the lower right of the inserted re tangle, we need to save the lo ation of point at the time the re tangle is inserted, move ba k to that position after the re tangle is inserted, and then move horizontally to the next pla e from whi h insert-re tangle is alled. If the inserted olumns are one hara ter wide, as they will be if single blanks and asterisks are used, the repositioning ommand is simply (forward- har 1); however, the width of a olumn may be greater than one. This means that the repositioning ommand should be written (forward har symbol-width). The symbol-width itself is the length of a graphblank and an be found using the expression (length graph-blank). The best pla e to bind the symbol-width variable to the value of the width of graph olumn is in the varlist of the let expression. These onsiderations lead to the following fun tion de nition: (defun graph-body-print (numbers-list) "Print a bar graph of the NUMBERS-LIST. The numbers-list onsists of the Y-axis values." (let ((height (apply 'max numbers-list)) (symbol-width (length graph-blank)) from-position) (while numbers-list (setq from-position (point)) (insert-re tangle ( olumn-of-graph height ( ar numbers-list))) (goto- har from-position) (forward- har symbol-width) ;; Draw graph olumn by olumn. (sit-for 0) (setq numbers-list ( dr numbers-list))) ;; Pla e point for X axis labels. (forward-line height) (insert "\n") ))

210

Chapter 15: Readying a Graph

The one unexpe ted expression in this fun tion is the (sit-for 0) expression 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: * * ** * **** *** **** ********* * ************ *************

15.2 The re ursive-graph-body-print Fun tion The graph-body-print fun tion may also be written re ursively. The re ursive solution is divided into two parts: an outside `wrapper' that uses a let expression to determine the values of several variables that need only be found on e, su h as the maximum height of the graph, and an inside fun tion that is alled re ursively to print the graph.

Need for Printed Axes

211

The `wrapper' is un ompli ated: (defun re ursive-graph-body-print (numbers-list) "Print a bar graph of the NUMBERS-LIST. The numbers-list onsists of the Y-axis values." (let ((height (apply 'max numbers-list)) (symbol-width (length graph-blank)) from-position) (re ursive-graph-body-print-internal numbers-list height symbol-width)))

The re ursive fun tion is a little more diÆ ult. It has four parts: the `do-again-test', the printing ode, the re ursive all, and the `next-stepexpression'. The `do-again-test' is an if expression that determines whether the numbers-list ontains any remaining elements; if it does, the fun tion prints one olumn of the graph using the printing ode and alls itself again. The fun tion alls itself again a

ording to the value produ ed by the `next-step-expression' whi h auses the all to a t on a shorter version of the numbers-list. (defun re ursive-graph-body-print-internal (numbers-list height symbol-width) "Print a bar graph. Used within re ursive-graph-body-print fun tion." (if numbers-list (progn (setq from-position (point)) (insert-re tangle ( olumn-of-graph height ( ar numbers-list))) (goto- har from-position) (forward- har symbol-width) (sit-for 0) ; Draw graph olumn by olumn. (re ursive-graph-body-print-internal ( dr numbers-list) height symbol-width))))

After installation, this expression an be tested; here is a sample: (re ursive-graph-body-print '(3 2 5 6 7 5 3 4 6 4 3 2 1))

Here is what re ursive-graph-body-print produ es: * ** * **** * **** *** * ********* ************ *************

212

Chapter 15: Readying a Graph

Either of these two fun tions, graph-body-print or re ursive-graphbody-print, reate the body of a graph.

15.3 Need for Printed Axes A graph needs printed axes, so you an orient yourself. For a do-on e proje t, it may be reasonable to draw the axes by hand using Ema s' Pi ture mode; but a graph drawing fun tion may be used more than on e. For this reason, I have written enhan ements to the basi print-graphbody fun tion that automati ally print labels for the horizontal and verti al axes. Sin e the label printing fun tions do not ontain mu h new material, I have pla ed their des ription in an appendix. See Appendix C, \A Graph with Labelled Axes", page 255.

15.4 Exer ise Write a line graph version of the graph printing fun tions.

Site-wide Initialization Files

213

16 Your `.ema s' File \You don't have to like Ema s to like it" { this seemingly paradoxi al statement is the se ret of GNU Ema s. The plain, `out of the box' Ema s is a generi tool. Most people who use it, ustomize it to suit themselves. GNU Ema s is mostly written in Ema s Lisp; this means that by writing expressions in Ema s Lisp you an hange or extend Ema s. There are those who appre iate Ema s' default on guration. After all, Ema s starts you in C mode when you edit a C le, starts you in Fortran mode when you edit a Fortran le, and starts you in Fundamental mode when you edit an unadorned le. This all makes sense, if you do not know who is going to use Ema s. Who knows what a person hopes to do with an unadorned le? Fundamental mode is the right default for su h a le, just as C mode is the right default for editing C ode. But when you do know who is going to use Ema s|you, yourself|then it makes sense to ustomize Ema s. For example, I seldom want Fundamental mode when I edit an otherwise undistinguished le; I want Text mode. This is why I ustomize Ema s: so it suits me. You an ustomize and extend Ema s by writing or adapting a `~/.ema s' le. This is your personal initialization le; its ontents, written in Ema s Lisp, tell Ema s what to do.1 A `~/.ema s' le ontains Ema s Lisp ode. You an write this ode yourself; or you an use Ema s' ustomize feature to write the ode for you. You an ombine your own expressions and auto-written Customize expressions in your `.ema s' le. (I myself prefer to write my own expressions, ex ept for those, parti ularly fonts, that I nd easier to manipulate using the ustomize ommand. I

ombine the two methods.) Most of this hapter is about writing expressions yourself. It des ribes a simple `.ema s' le; for more information, see se tion \The Init File" in The GNU Ema s Manual, and se tion \The Init File" in The GNU Ema s Lisp Referen e Manual.

16.1 Site-wide Initialization Files In addition to your personal initialization le, Ema s automati ally loads various site-wide initialization les, if they exist. These have the same form as your `.ema s' le, but are loaded by everyone. 1

You may also add `.el' to `~/.ema s' and all it a `~/.ema s.el' le. In the past, you were forbidden to type the extra keystrokes that the name `~/.ema s.el' requires, but now you may. The new format is onsistent with the Ema s Lisp le naming

onventions; the old format saves typing.

214

Chapter 16: Your `.ema s' File

Two site-wide initialization les, `site-load.el' and `site-init.el', are loaded into Ema s and then `dumped' if a `dumped' version of Ema s is

reated, as is most ommon. (Dumped opies of Ema s load more qui kly. However, on e a le is loaded and dumped, a hange to it does not lead to a hange in Ema s unless you load it yourself or re-dump Ema s. See se tion \Building Ema s" in The GNU Ema s Lisp Referen e Manual, and the `INSTALL' le.) Three other site-wide initialization les are loaded automati ally ea h time you start Ema s, if they exist. These are `site-start.el', whi h is loaded before your `.ema s' le, and `default.el', and the terminal type le, whi h are both loaded after your `.ema s' le. Settings and de nitions in your `.ema s' le will overwrite on i ting settings and de nitions in a `site-start.el' le, if it exists; but the settings and de nitions in a `default.el' or terminal type le will overwrite those in your `.ema s' le. (You an prevent interferen e from a terminal type le by setting term-file-prefix to nil. See Se tion 16.11, \A Simple Extension", page 224.) The `INSTALL' le that omes in the distribution ontains des riptions of the `site-init.el' and `site-load.el' les. The `loadup.el', `startup.el', and `loaddefs.el' les ontrol loading. These les are in the `lisp' dire tory of the Ema s distribution and are worth perusing. The `loaddefs.el' le ontains a good many suggestions as to what to put into your own `.ema s' le, or into a site-wide initialization le.

16.2 Spe ifying Variables using def ustom You an spe ify variables using def ustom so that you and others an then an use Ema s' ustomize feature to set their values. (You annot use

ustomize to write fun tion de nitions; but you an write defuns in your `.ema s' le. Indeed, you an write any Lisp expression in your `.ema s' le.) The ustomize feature depends on the def ustom spe ial form. Although you an use defvar or setq for variables that users set, the def ustom spe ial form is designed for the job. You an use your knowledge of defvar for writing the rst three arguments for def ustom. The rst argument to def ustom is the name of the variable. The se ond argument is the variable's initial value, if any; and this value is set only if the value has not already been set. The third argument is the do umentation. The fourth and subsequent arguments to def ustom spe ify types and options; these are not featured in defvar. (These arguments are optional.) Ea h of these arguments onsists of a keyword followed by a value. Ea h keyword starts with the hara ter :.

Spe ifying Variables using def ustom

215

For example, the ustomizable user option variable text-mode-hook looks like this: (def ustom text-mode-hook nil "Normal hook run when entering Text mode and many related modes." :type 'hook :options '(turn-on-auto-fill flyspell-mode) :group 'data)

The name of the variable is text-mode-hook; it has no default value; and its do umentation string tells you what it does. The :type keyword tells Ema s what kind of data text-mode-hook should be set to and how to display the value in a Customization bu er. The :options keyword spe i es a suggested list of values for the variable. Currently, you an use :options only for a hook. The list is only a suggestion; it is not ex lusive; a person who sets the variable may set it to other values; the list shown following the :options keyword is intended to o er onvenient hoi es to a user. Finally, the :group keyword tells the Ema s Customization ommand in whi h group the variable is lo ated. This tells where to nd it. For more information, see se tion \Writing Customization De nitions" in The GNU Ema s Lisp Referen e Manual. Consider text-mode-hook as an example. There are two ways to ustomize this variable. You an use the ustomization ommand or write the appropriate expressions yourself. Using the ustomization ommand, you an type: M-x ustomize

and nd that the group for editing les of data is alled `data'. Enter that group. Text Mode Hook is the rst member. You an li k on its various options to set the values. After you li k on the button to Save for Future Sessions

Ema s will write an expression into your `.ema s' le. It will look like this: ( ustom-set-variables ;; ustom-set-variables was added by Custom -;; don't edit or ut/paste it! ;; Your init file should ontain only one su h instan e. '(text-mode-hook (quote (turn-on-auto-fill text-mode-hook-identify))))

(The text-mode-hook-identify fun tion tells toggle-text-mode-autofill whi h bu ers are in Text mode.) In spite of the warning, you ertainly may edit, ut, and paste the expression! I do all time. The purpose of the warning is to s are those who do not know what they are doing, so they do not inadvertently generate an error.

216

Chapter 16: Your `.ema s' File

The ustom-set-variables works somewhat di erently than a setq. While I have never learned the di eren es, I do modify the ustom-setvariables expressions in my `.ema s' le by hand: I make the hanges in what appears to me to be a reasonable manner and have not had any problems. Others prefer to use the Customization ommand and let Ema s do the work for them. Another ustom-set-... fun tion is ustom-set-fa es. This fun tion sets the various font fa es. Over time, I have set a onsiderable number of fa es. Some of the time, I re-set them using ustomize; other times, I simply edit the ustom-set-fa es expression in my `.ema s' le itself. The se ond way to ustomize your text-mode-hook is to set it yourself in your `.ema s' le using ode that has nothing to do with the ustomset-... fun tions. When you do this, and later use ustomize, you will see a message that says this option has been hanged outside the ustomize buffer.

This message is only a warning. If you li k on the button to Save for Future Sessions

Ema s will write a ustom-set-... expression near the end of your `.ema s' le that will be evaluated after your hand-written expression. It will, therefore, overrule your hand-written expression. No harm will be done. When you do this, however, be areful to remember whi h expression is a tive; if you forget, you may onfuse yourself. So long as you remember where the values are set, you will have no trouble. In any event, the values are always set in your initialization le, whi h is usually alled `.ema s'. I myself use ustomize for hardly anything. Mostly, I write expressions myself.

16.3 Beginning a `.ema s' File When you start Ema s, it loads your `.ema s' le unless you tell it not to by spe ifying `-q' on the ommand line. (The ema s -q ommand gives you a plain, out-of-the-box Ema s.) A `.ema s' le ontains Lisp expressions. Often, these are no more than expressions to set values; sometimes they are fun tion de nitions. See se tion \The Init File `~/.ema s'" in The GNU Ema s Manual, for a short des ription of initialization les. This hapter goes over some of the same ground, but is a walk among extra ts from a omplete, long-used `.ema s' le|my own. The rst part of the le onsists of omments: reminders to myself. By now, of ourse, I remember these things, but when I started, I did not.

Text and Auto Fill Mode

217

;;;; Bob's .ema s file ; Robert J. Chassell ; 26 September 1985

Look at that date! I started this le a long time ago. I have been adding to it ever sin e. ; ; ; ;

Ea h se tion in this file is introdu ed by a line beginning with four semi olons; and ea h entry is introdu ed by a line beginning with three semi olons.

This des ribes the usual onventions for omments in Ema s Lisp. Everything on a line that follows a semi olon is a omment. Two, three, and four semi olons are used as se tion and subse tion markers. (See se tion \Comments" in The GNU Ema s Lisp Referen e Manual, for more about

omments.) ;;;; The Help Key ; Control-h is the help key; ; after typing ontrol-h, type a letter to ; indi ate the subje t about whi h you want help. ; For an explanation of the help fa ility, ; type ontrol-h two times in a row.

Just remember: type C-h two times for help. ; ; ; ;

To find out about any mode, type ontrol-h m while in that mode. For example, to find out about mail mode, enter mail mode and then type

ontrol-h m.

`Mode help', as I all this, is very helpful. Usually, it tells you all you need to know. Of ourse, you don't need to in lude omments like these in your `.ema s' le. I in luded them in mine be ause I kept forgetting about Mode help or the onventions for omments|but I was able to remember to look here to remind myself.

16.4 Text and Auto Fill Mode Now we ome to the part that `turns on' Text mode and Auto Fill mode. ;;; Text mode and Auto Fill mode ; The next three lines put Ema s into Text mode ; and Auto Fill mode, and are for writers who ; want to start writing prose rather than ode. (setq default-major-mode 'text-mode) (add-hook 'text-mode-hook 'text-mode-hook-identify) (add-hook 'text-mode-hook 'turn-on-auto-fill)

218

Chapter 16: Your `.ema s' File

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-hookidentify to the variable alled text-mode-hook and then adds turn-onauto-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 onveniently 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)

16.5 Mail Aliases Here is a setq that `turns on' mail aliases, along with more reminders. ;;; Mail mode ; To enter mail mode, type `C-x m' ; To enter RMAIL (for reading mail), ; type `M-x rmail' (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.6 Indent Tabs Mode By default, Ema s inserts tabs in pla e of multiple spa es when it formats a region. (For example, you might indent many lines of text all at on e with the indent-region ommand.) Tabs look ne on a terminal or with ordinary printing, but they produ e badly indented output when you use TEX or Texinfo sin e TEX ignores tabs.

220

Chapter 16: Your `.ema s' File

The following turns o Indent Tabs mode: ;;; Prevent Extraneous Tabs (setq-default indent-tabs-mode nil)

Note that this line uses setq-default rather than the setq ommand that we have seen before. The setq-default ommand sets values only in bu ers that do not have their own lo al values for the variable. See se tions \Tabs vs. Spa es" and \Lo al Variables in Files" in The GNU Ema s Manual.

16.7 Some Keybindings Now for some personal keybindings: ;;; Compare windows (global-set-key "\C- w" ' ompare-windows)

ompare-windows is a nifty ommand that ompares the text in your

urrent window with text in the next window. It makes the omparison by starting at point in ea h window, moving over text in ea h window as far as they mat h. I use this ommand all the time. This also shows how to set a key globally, for all modes. The ommand is global-set-key. It is followed by the keybinding. In a `.ema s' le, the keybinding is written as shown: \C- stands for ` ontrol ', whi h means `press the ontrol key and the key at the same time'. The w means `press the w key'. The keybinding is surrounded by double quotation marks. In do umentation, you would write this as C- w. (If you were binding a hMETAi key, su h as M- , rather than a hCTLi key, you would write \M- . See se tion \Rebinding Keys in Your Init File" in The GNU Ema s Manual, for details.) The ommand invoked by the keys is ompare-windows. Note that

ompare-windows is pre eded by a single quote; otherwise, Ema s would rst try to evaluate the symbol to determine its value. These three things, the double quotation marks, the ba kslash before the `C', and the single quote mark are ne essary parts of keybinding that I tend to forget. Fortunately, I have ome to remember that I should look at my existing `.ema s' le, and adapt what is there. As for the keybinding itself: C- w. This ombines the pre x key, C- , with a single hara ter, in this ase, w. This set of keys, C- followed by a single hara ter, is stri tly reserved for individuals' own use. (I all these `own' keys, sin e these are for my own use.) You should always be able to

reate su h a keybinding for your own use without stomping on someone else's keybinding. If you ever write an extension to Ema s, please avoid taking any of these keys for publi use. Create a key like C- C-w instead. Otherwise, we will run out of `own' keys.

Keymaps

221

Here is another keybinding, with a omment: ;;; Keybinding for `o

ur' ; I use o

ur a lot, so let's bind it to a key: (global-set-key "\C- o" 'o

ur)

The o

ur ommand shows all the lines in the urrent bu er that ontain a mat h for a regular expression. Mat hing lines are shown in a bu er alled `*O

ur*'. That bu er serves as a menu to jump to o

urren es. Here is how to unbind a key, so it does not work: ;;; Unbind `C-x f' (global-unset-key "\C-xf")

There is a reason for this unbinding: I found I inadvertently typed C-x f when I meant to type C-x C-f. Rather than nd a le, as I intended, I a

identally set the width for lled text, almost always to a width I did not want. Sin e I hardly ever reset my default width, I simply unbound the key. The following rebinds an existing key: ;;; Rebind `C-x C-b' for `buffer-menu' (global-set-key "\C-x\C-b" 'buffer-menu)

By default, C-x C-b runs the list-buffers ommand. This ommand lists your bu ers in another window. Sin e I almost always want to do something in that window, I prefer the buffer-menu ommand, whi h not only lists the bu ers, but moves point into that window.

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.9 Loading Files Many people in the GNU Ema s ommunity have written extensions to Ema s. As time goes by, these extensions are often in luded in new releases. For example, the Calendar and Diary pa kages are now part of the standard GNU Ema s. (Cal , whi h I onsider a vital part of Ema s, would be part of the standard distribution ex ept that it was so large it was pa kaged separately and no one has hanged that.) You an use a load ommand to evaluate a omplete le and thereby install all the fun tions and variables in the le into Ema s. For example: (load "~/ema s/slowsplit")

This evaluates, i.e. loads, the `slowsplit.el' le or if it exists, the faster, byte ompiled `slowsplit.el ' le from the `ema s' sub-dire tory of your home dire tory. The le ontains the fun tion split-window-quietly, whi h John Robinson wrote in 1989. The split-window-quietly fun tion splits a window with the minimum of redisplay. I installed it in 1989 be ause it worked well with the slow 1200 baud terminals I was then using. Nowadays, I only o

asionally ome a ross su h a slow onne tion, but I ontinue to use the fun tion be ause I like the way it leaves the bottom half of a bu er in the lower of the new windows and the top half in the upper window.

Autoloading

223

To repla e the key binding for the default split-window-verti ally, you must also unset that key and bind the keys to split-window-quietly, like this: (global-unset-key "\C-x2") (global-set-key "\C-x2" 'split-window-quietly)

If you load many extensions, as I do, then instead of spe ifying the exa t lo ation of the extension le, as shown above, you an spe ify that dire tory as part of Ema s' load-path. Then, when Ema s loads a le, it will sear h that dire tory as well as its default list of dire tories. (The default list is spe i ed in `paths.h' when Ema s is built.) The following ommand adds your `~/ema s' dire tory to the existing load path: ;;; Ema s Load Path (setq load-path ( ons "~/ema s" load-path))

In identally, load-library is an intera tive interfa e to the load fun tion. The omplete fun tion looks like this: (defun load-library (library) "Load the library named LIBRARY. This is an interfa e to the fun tion `load'." (intera tive "sLoad library: ") (load library))

The name of the fun tion, load-library, omes from the use of `library' as a onventional synonym for ` le'. The sour e for the load-library ommand is in the `files.el' library. Another intera tive ommand that does a slightly di erent job is loadfile. See se tion \Libraries of Lisp Code for Ema s" in The GNU Ema s Manual, for information on the distin tion between load-library and this

ommand.

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 evaluates 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' library 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)

(html-helper-mode is an alternative to html-mode, whi h is a standard part of the distribution). This expression autoloads the html-helper-mode fun tion. It takes it from the `html-helper-mode.el' le (or from the byte ompiled le `html-helper-mode.el ', if it exists.) The le must be lo ated in a dire tory spe i ed by load-path. The do umentation says that this is a mode to help you edit do uments written in the HyperText Markup Language. You an all this mode intera tively by typing M-x html-helper-mode. (You need to dupli ate the fun tion's regular do umentation in the autoload expression be ause the regular fun tion is not yet loaded, so its do umentation is not available.) See se tion \Autoload" in The GNU Ema s Lisp Referen e Manual, for more information.

16.11 A Simple Extension:

line-to-top-of-window

Here is a simple extension to Ema s that moves the line point is on to the top of the window. I use this all the time, to make text easier to read. You an put the following ode into a separate le and then load it from your `.ema s' le, or you an in lude it within your `.ema s' le.

A Simple Extension: line-to-top-of-window

225

Here is the de nition: ;;; Line to top of window; ;;; repla e three keystroke sequen e C-u 0 C-l (defun line-to-top-of-window () "Move the line point is on to top of window." (intera tive) (re enter 0))

Now for the keybinding. Nowadays, fun tion keys as well as mouse button events and non-as ii

hara ters are written within square bra kets, without quotation marks. (In Ema s version 18 and before, you had to write di erent fun tion key bindings for ea h di erent make of terminal.) I bind line-to-top-of-window to my hF6i fun tion key like this: (global-set-key [f6â„„ 'line-to-top-of-window)

For more information, see se tion \Rebinding Keys in Your Init File" in The GNU Ema s Manual. If you run two versions of GNU Ema s, su h as versions 20 and 21, and use one `.ema s' le, you an sele t whi h ode to evaluate with the following

onditional: ( ond ((string-equal (number-to-string 20) (substring (ema s-version) 10 12)) ;; evaluate version 20 ode ( ... )) ((string-equal (number-to-string 21) (substring (ema s-version) 10 12)) ;; evaluate version 21 ode ( ... )))

For example, in ontrast to version 20, version 21 blinks its ursor by default. I hate su h blinking, as well as some other features in version 21, so I pla ed the following in my `.ema s' le2: (if (string-equal "21" (substring (ema s-version) 10 12)) (progn (blink- ursor-mode 0) ;; Insert newline when you press `C-n' (next-line) ;; at the end of the buffer (setq next-line-add-newlines t) ;; Turn on image viewing (auto-image-file-mode 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 ;; Turn on menu bar (this bar has text) ;; (Use numeri argument to turn on) (menu-bar-mode 1) ;; Turn off tool bar (this bar has i ons) ;; (Use numeri argument to turn on) (tool-bar-mode nil) ;; Turn off tooltip mode for tool bar ;; (This mode auses i on explanations to pop up) ;; (Use numeri argument to turn on) (tooltip-mode nil) ;; If tooltips turned on, make tips appear promptly (setq tooltip-delay 0.1) ; default is one se ond ))

(You will note that instead of typing (number-to-string 21), I de ided to save typing and wrote `21' as a string, "21", rather than onvert it from an integer to a string. In this instan e, this expression is better than the longer, but more general (number-to-string 21). However, if you do not know ahead of time what type of information will be returned, then the number-to-string fun tion will be needed.)

16.12 X11 Colors You an spe ify olors when you use Ema s with the MIT X Windowing system. I dislike the default olors and spe ify my own. Here are the expressions in my `.ema s' le that set values: ;; Set ursor olor (set- ursor- olor "white") ;; Set mouse olor (set-mouse- olor "white") ;; Set foreground and ba kground (set-foreground- olor "white") (set-ba kground- olor "darkblue") ;;; Set highlighting olors for isear h and drag (set-fa e-foreground 'highlight "white") (set-fa e-ba kground 'highlight "blue") (set-fa e-foreground 'region " yan") (set-fa e-ba kground 'region "blue") (set-fa e-foreground 'se ondary-sele tion "skyblue") (set-fa e-ba kground 'se ondary-sele tion "darkblue")

A Modi ed Mode Line

227

;; Set alendar highlighting olors (setq alendar-load-hook '(lambda () (set-fa e-foreground 'diary-fa e "skyblue") (set-fa e-ba kground 'holiday-fa e "slate blue") (set-fa e-foreground 'holiday-fa e "white")))

The various shades of blue soothe my eye and prevent me from seeing the s reen i ker. Alternatively, I ould have set my spe i ations in various X initialization les. For example, I ould set the foreground, ba kground, ursor, and pointer (i.e., mouse) olors in my `~/.Xresour es' le like this: Ema s*foreground: Ema s*ba kground: Ema s* ursorColor: Ema s*pointerColor:

white darkblue white white

In any event, sin e it is not part of Ema s, I set the root olor of my X window in my `~/.xinitr ' le, like this3: # I use TWM for window manager. xsetroot -solid Navy -fg white &

16.13 Mis ellaneous Settings for a `.ema s' File Here are a few mis ellaneous settings: Set the shape and olor of the mouse ursor: ; ; ; ;

Cursor shapes are defined in `/usr/in lude/X11/ ursorfont.h'; for example, the `target' ursor is number 128; the `top_left_arrow' ursor is number 132.

(let ((mpointer (x-get-resour e "*mpointer" "*ema s*mpointer"))) ;; If you have not set your mouse pointer ;; then set it, otherwise leave as is: (if (eq mpointer nil) (setq mpointer "132")) ; top_left_arrow (setq x-pointer-shape (string-to-int mpointer)) (set-mouse- olor "white")) 3

I o

asionally run more modern window managers, su h as Saw sh with GNOME, Enlightenment, SCWM, or KDE; in those ases, I often spe ify an image rather than a plain olor.

228

Chapter 16: Your `.ema s' File

16.14 A Modi ed Mode Line Finally, a feature I really like: a modi ed mode line. When I work over a network, I forget whi h ma hine I am using. Also, I tend to I lose tra k of where I am, and whi h line point is on. So I reset my mode line to look like this: -:-- foo.texi

rattlesnake:/home/bob/

Line 1

(Texinfo Fill) Top

I am visiting a le alled `foo.texi', on my ma hine `rattlesnake' in my `/home/bob' bu er. I am on line 1, in Texinfo mode, and am at the top of the bu er. My `.ema s' le has a se tion that looks like this: ;; 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 appears (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 Referen 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.

231

debug

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 Programs" 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 Ce (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 advantage 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 expression 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

Eventually, the bu er will look like this: ---------- Buffer: *Ba ktra e* ---------Debugger entered--beginning evaluation of fun tion all form: * (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(5) eval((triangle-bugged 5)) eval-last-sexp-1(nil) eval-last-sexp(nil)

all-intera tively(eval-last-sexp) ---------- Buffer: *Ba ktra e* ----------

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* ----------

By typing d, you were able to step through the fun tion. You an quit a `*Ba ktra e*' bu er by typing q in it; this quits the tra e, but does not an el debug-on-entry. To an el the e e t of debug-on-entry, all an el-debug-on-entry and the name of the fun tion, like this: M-x an el-debug-on-entry RET triangle-bugged RET

(If you are reading this in Info, an el debug-on-entry now.)

17.3

debug-on-quit

and (debug)

In addition to setting debug-on-error or alling debug-on-entry, there are two other ways to start debug. You an start debug whenever you type C-g (keyboard-quit) by setting the variable debug-on-quit to t. This is useful for debugging in nite loops.

The edebug Sour e Level Debugger

235

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.

17.4 The edebug Sour e Level Debugger Edebug is a sour e level debugger. Edebug normally displays the sour e of the ode you are debugging, with an arrow at the left that shows whi h line you are urrently exe uting. You an walk through the exe ution of a fun tion, line by line, or run qui kly until rea hing a breakpoint where exe ution stops. Edebug is des ribed in se tion \Edebug" in The GNU Ema s Lisp Referen e Manual. Here is a bugged fun tion de nition for triangle-re ursively. See Se tion 11.3.4, \Re ursion in pla e of a ounter", page 137, for a review of it. (defun triangle-re ursively-bugged (number) "Return sum of numbers 1 through NUMBER in lusive. Uses re ursion." (if (= number 1) 1 (+ number (triangle-re ursively-bugged (1= number))))) ; Error here.

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 (evaldefun). (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 positioning 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)))))

When you press says:

hSPCi

; Error here.

on e again, you will produ e an error message that

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 Referen e Manual.

17.5 Debugging Exer ises 

     

Install the ount-words-region fun tion and then ause it to enter the built-in debugger when you all it. Run the ommand on a region

ontaining two words. You will need to press d a remarkable number of times. On your system, is a `hook' alled after the ommand nishes? (For information on hooks, see se tion \Command Loop Overview" in The GNU Ema s Lisp Referen e Manual.) Copy ount-words-region into the `*s rat h*' bu er, instrument the fun tion for Edebug, and walk through its exe ution. The fun tion does not need to have a bug, although you an introdu e one if you wish. If the fun tion la ks a bug, the walk-through ompletes without problems. While running Edebug, type ? to see a list of all the Edebug ommands. (The global-edebug-prefix is usually C-x X, i.e. hCTLi-x followed by an upper ase X; use this pre x for ommands made outside of the Edebug debugging bu er.) In the Edebug debugging bu er, use the p (edebug-boun e-point)

ommand to see where in the region the ount-words-region is working. Move point to some spot further down fun tion and then type the h (edebug-goto-here) ommand to jump to that lo ation. Use the t (edebug-tra e-mode) ommand to ause Edebug to walk through the fun tion on its own; use an upper ase T for edebug-Tra efast-mode. Set a breakpoint, then run Edebug in Tra e mode until it rea hes the stopping point.

238

Chapter 17: Debugging

Con lusion

239

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 easyto-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, \Review", 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

Appendix A The the-the Fun tion Sometimes when you you write text, you dupli ate words|as with \you you" near the beginning of this senten e. I nd that most frequently, I dupli ate \the'; hen e, I all the fun tion for dete ting dupli ated words, the-the. As a rst step, you ould use the following regular expression to sear h for dupli ates: \\(\\w+[ \t\nâ„„+\\)\\1

This regexp mat hes one or more word- onstituent hara ters followed by one or more spa es, tabs, or newlines. However, it does not dete t dupli ated words on di erent lines, sin e the ending of the rst word, the end of the line, is di erent from the ending of the se ond word, a spa e. (For more information about regular expressions, see Chapter 12, \Regular Expression Sear hes", page 149, as well as se tion \Syntax of Regular Expressions" in The GNU Ema s Manual, and se tion \Regular Expressions" in The GNU Ema s Lisp Referen e Manual.) You might try sear hing just for dupli ated word- onstituent hara ters but that does not work sin e the pattern dete ts doubles su h as the two o

urren es of `th' in `with the'. Another possible regexp sear hes for word- onstituent hara ters followed by non-word- onstituent hara ters, redupli ated. Here, `\\w+' mat hes one or more word- onstituent hara ters and `\\W*' mat hes zero or more nonword- onstituent hara ters. \\(\\(\\w+\\)\\W*\\)\\1

Again, not useful. Here is the pattern that I use. It is not perfe t, but good enough. `\\b' mat hes the empty string, provided it is at the beginning or end of a word; `[^ \n\tâ„„+' mat hes one or more o

urren es of any hara ters that are not an -sign, spa e, newline, or tab. \\b\\([^ \n\tâ„„+\\)[ \n\tâ„„+\\1\\b

One an write more ompli ated expressions, but I found that this expression is good enough, so I use it. Here is the the-the fun tion, as I in lude it in my `.ema s' le, along with a handy global key binding: (defun the-the () "Sear h forward for for a dupli ated word." (intera tive) (message "Sear hing for for dupli ated words ...") (push-mark)

242

Appendix A: The the-the Fun tion ;; This regexp is not perfe t ;; but is fairly good over all: (if (re-sear h-forward "\\b\\([^ \n\tâ„„+\\)[ \n\tâ„„+\\1\\b" nil 'move) (message "Found dupli ated word.") (message "End of buffer"))) ;; Bind `the-the' to C- \ (global-set-key "\C- \\" 'the-the)

Here is test text: one two two three four five five six seven

You an substitute the other regular expressions shown above in the fun tion de nition and try ea h of them on this list.

The rotate-yank-pointer Fun tion

243

Appendix B Handling the Kill Ring The kill ring is a list that is transformed into a ring by the workings of the

rotate-yank-pointer fun tion. The yank and yank-pop ommands use the rotate-yank-pointer fun tion. This appendix des ribes the rotate-yankpointer fun tion as well as both the yank and the yank-pop ommands.

B.1 The rotate-yank-pointer Fun tion The rotate-yank-pointer fun tion hanges the element in the kill ring to whi h kill-ring-yank-pointer points. For example, it an hange kill-ring-yank-pointer from pointing to the se ond element to point to the third element. Here is the ode for rotate-yank-pointer: (defun rotate-yank-pointer (arg) "Rotate the yanking point in the kill ring." (intera tive "p") (let ((length (length kill-ring))) (if (zerop length) ;; then-part (error "Kill ring is empty") ;; else-part (setq kill-ring-yank-pointer (nth dr (% (+ arg (- length (length kill-ring-yank-pointer))) length) kill-ring)))))

The rotate-yank-pointer fun tion looks omplex, but as usual, it an be understood by taking it apart pie e by pie e. First look at it in skeletal form: (defun rotate-yank-pointer (arg) "Rotate the yanking point in the kill ring." (intera tive "p") (let varlist body ...)

This fun tion takes one argument, alled arg. It has a brief do umentation string; and it is intera tive with a small `p', whi h means that the argument must be a pro essed pre x passed to the fun tion as a number. The body of the fun tion de nition is a let expression, whi h itself has a body as well as a varlist.

244

Appendix B: Handling the Kill Ring

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.

B.1.1 The Body of rotate-yank-pointer The body of rotate-yank-pointer is a let expression and the body of the let expression is an if expression. The purpose of the if expression is to nd out whether there is anything in the kill ring. If the kill ring is empty, the error fun tion stops evaluation of the fun tion and prints a message in the e ho area. On the other hand, if the kill ring has something in it, the work of the fun tion is done. Here is the if-part and then-part of the if expression: (if (zerop length) (error "Kill ring is empty") ...

; if-part ; then-part

If there is not anything in the kill ring, its length must be zero and an error message sent to the user: `Kill ring is empty'. The if expression uses the fun tion zerop whi h returns true if the value it is testing is zero. When zerop tests true, the then-part of the if is evaluated. The then-part is a list starting with the fun tion error, whi h is a fun tion that is similar to the message fun tion (see Se tion 1.8.5, \message", page 16), in that it prints a one-line message in the e ho area. However, in addition to printing a message, error also stops evaluation of the fun tion within whi h it is embedded. This means that the rest of the fun tion will not be evaluated if the length of the kill ring is zero. (In my opinion, it is slightly misleading, at least to humans, to use the term `error' as the name of the error fun tion. A better term would be ` an el'. Stri tly speaking, of ourse, you annot point to, mu h less rotate a pointer to a list that has no length, so from the point of view of the

omputer, the word `error' is orre t. But a human expe ts to attempt this sort of thing, if only to nd out whether the kill ring is full or empty. This is an a t of exploration. (From the human point of view, the a t of exploration and dis overy is not ne essarily an error, and therefore should not be labelled as one, even in the bowels of a omputer. As it is, the ode in Ema s implies that a human who is a ting virtuously, by exploring his or her environment, is making an

The else-part of the if expression

245

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.)

The else-part of the if expression The else-part of the if expression is dedi ated to setting the value of kill-ring-yank-pointer when the kill ring has something in it. The ode

looks like this:

(setq kill-ring-yank-pointer (nth dr (% (+ arg (- length (length kill-ring-yank-pointer))) length) kill-ring)))))

This needs some examination. Clearly, kill-ring-yank-pointer is being set to be equal to some dr of the kill ring, using the nth dr fun tion that is des ribed in an earlier se tion. (See Se tion 8.5, \ opy-region-as-kill", page 102.) But exa tly how does it do this? Before looking at the details of the ode let's rst onsider the purpose of the rotate-yank-pointer fun tion. The rotate-yank-pointer fun tion hanges what kill-ring-yankpointer points to. If kill-ring-yank-pointer starts by pointing to the rst element of a list, a all to rotate-yank-pointer auses it to point to the se ond element; and if kill-ring-yank-pointer points to the se ond element, a all to rotate-yank-pointer auses it to point to the third element. (And if rotate-yank-pointer is given an argument greater than 1, it jumps the pointer that many elements.) The rotate-yank-pointer fun tion uses setq to reset what the killring-yank-pointer points to. If kill-ring-yank-pointer points to the rst element of the kill ring, then, in the simplest ase, the rotate-yankpointer fun tion must ause it to point to the se ond element. Put another way, kill-ring-yank-pointer must be reset to have a value equal to the

dr of the kill ring. That is, under these ir umstan es, (setq kill-ring-yank-pointer ("some text" "a different pie e of text" "yet more text")) (setq kill-ring ("some text" "a different pie e of text" "yet more text"))

246

Appendix B: Handling the Kill Ring

the ode should do this: (setq kill-ring-yank-pointer ( dr kill-ring))

As a result, the kill-ring-yank-pointer will look like this: kill-ring-yank-pointer ) ("a different pie e of text" "yet more text"))

The a tual setq expression uses the nth dr fun tion to do the job. As we have seen before (see Se tion 7.3, \nth dr", page 85), the nth dr fun tion works by repeatedly taking the dr of a list|it takes the dr of the dr of the dr . . . The two following expressions produ e the same result: (setq kill-ring-yank-pointer ( dr kill-ring)) (setq kill-ring-yank-pointer (nth dr 1 kill-ring))

In the rotate-yank-pointer fun tion, however, the rst argument to nth dr is a rather omplex looking expression with lots of arithmeti inside of it:

(% (+ arg (- length (length kill-ring-yank-pointer))) length)

As usual, we need to look at the most deeply embedded expression rst and then work our way towards the light. The most deeply embedded expression is (length kill-ring-yankpointer). This nds the length of the urrent value of the kill-ringyank-pointer. (Remember that the kill-ring-yank-pointer is the name of a variable whose value is a list.) The measurement of the length is inside the expression: (- length (length kill-ring-yank-pointer))

In this expression, the rst length is the variable that was assigned the length of the kill ring in the let statement at the beginning of the fun tion. (One might think this fun tion would be learer if the variable length were named length-of-kill-ring instead; but if you look at the text of the whole fun tion, you will see that it is so short that naming this variable length is not a bother, unless you are pulling the fun tion apart into very tiny pie es as we are doing here.) So the line (- length (length kill-ring-yank-pointer)) tells the differen e between the length of the kill ring and the length of the list whose name is kill-ring-yank-pointer. To see how all this ts into the rotate-yank-pointer fun tion, let's begin by analyzing the ase where kill-ring-yank-pointer points to the rst element of the kill ring, just as kill-ring does, and see what happens when rotate-yank-pointer is alled with an argument of 1.

The % remainder fun tion

247

The variable length and the value of the expression (length kill-ringyank-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)

The % remainder fun tion To understand (% 1 length), we need to understand %. A

ording to its do umentation (whi h I just found by typing C-h f % hRETi), the % fun tion returns the remainder of its rst argument divided by its se ond argument. For example, the remainder of 5 divided by 2 is 1. (2 goes into 5 twi e with a remainder of 1.) What surprises people who don't often do arithmeti is that a smaller number an be divided by a larger number and have a remainder. In the example we just used, 5 was divided by 2. We an reverse that and ask, what is the result of dividing 2 by 5? If you an use fra tions, the answer is obviously 2/5 or .4; but if, as here, you an only use whole numbers, the result has to be something di erent. Clearly, 5 an go into 2 zero times, but what of the remainder? To see what the answer is, onsider a ase that has to be familiar from hildhood:  5 divided by 5 is 1 with a remainder of 0;  6 divided by 5 is 1 with a remainder of 1;  7 divided by 5 is 1 with a remainder of 2.  Similarly, 10 divided by 5 is 2 with a remainder of 0;  11 divided by 5 is 2 with a remainder of 1;  12 divided by 5 is 1 with a remainder of 2. By onsidering the ases as parallel, we an see that  zero divided by 5 must be zero with a remainder of zero;  1 divided by 5 must be zero with a remainder of 1;  2 divided by 5 must be zero with a remainder of 2; and so on.

248

Appendix B: Handling the Kill Ring

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 % expression 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.

Pointing to the last element The nal question is, what happens if the kill-ring-yank-pointer is set to the last element of the kill ring? Will a all to rotate-yank-pointer mean that nothing more an be taken from the kill ring? The answer is no. What happens is di erent and useful. The kill-ring-yank-pointer is set to point to the beginning of the kill ring instead.

249

yank

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)

This expression an be evaluated by looking at the most embedded inner expression rst and working outwards: The value of (- 5 1) is 4; the sum of (+ 1 4) is 5; and the remainder of dividing 5 by 5 is zero. So what rotate-yank-pointer will do is (setq kill-ring-yank-pointer (nth dr 0 kill-ring))

whi h will set the kill-ring-yank-pointer to point to the beginning of the kill ring. So what happens with su

essive alls to rotate-yank-pointer is that it moves the kill-ring-yank-pointer from element to element in the kill ring until it rea hes the end; then it jumps ba k to the beginning. And this is why the kill ring is alled a ring, sin e by jumping ba k to the beginning, it is as if the list has no end! (And what is a ring, but an entity with no end?)

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 (intera tive "*P") (rotate-yank-pointer (if (listp arg) 0 (if (eq arg '-) -1 (1- arg)))) (push-mark (point)) (insert ( ar kill-ring-yank-pointer)) (if ( onsp arg) (ex hange-point-and-mark)))

Glan ing over this ode, we an understand the last few lines readily enough. The mark is pushed, that is, remembered; then the rst element (the ar) of what the kill-ring-yank-pointer points to is inserted; and then, if the argument passed the fun tion is a ons, point and mark are ex hanged so the point is put in the front of the inserted text rather than at the end. This option is explained in the do umentation. The fun tion itself is intera tive with "*P". This means it will not work on a read-only bu er, and that the unpro essed pre x argument is passed to the fun tion.

Passing the argument The hard part of yank is understanding the omputation that determines the value of the argument passed to rotate-yank-pointer. Fortunately, it is not so diÆ ult as it looks at rst sight. What happens is that the result of evaluating one or both of the if expressions will be a number and that number will be the argument passed to rotate-yank-pointer. Laid out with omments, the ode looks like this: (if (listp arg) 0 (if (eq arg '-) -1 (1- arg))))

; ; ; ; ;

if-part then-part else-part, inner if inner if's then-part inner if's else-part

This ode onsists of two if expression, one the else-part of the other. The rst or outer if expression tests whether the argument passed to yank is a list. Oddly enough, this will be true if yank is alled without an argument|be ause then it will be passed the value of nil for the optional argument and an evaluation of (listp nil) returns true! So, if no argument is passed to yank, the argument passed to rotate-yank-pointer inside of yank is zero. This means the pointer is not moved and the rst element to whi h kill-ring-yank-pointer points is inserted, as we expe t. Similarly, if the argument for yank is C-u, this will be read as a list, so again, a zero will be passed to rotate-yank-pointer. (C-u produ es an unpro essed pre x argument of (4), whi h is a list of one element.) At the same time, later in the fun tion, this argument will be read as a ons so point will be put in the

Passing a negative argument

251

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.

Passing a negative argument Finally, the question arises, what happens if either the remainder fun tion, %, or the nth dr fun tion is passed a negative argument, as they quite well may? The answers an be found by a qui k test. When (% -1 5) is evaluated, a negative number is returned; and if nth dr is alled with a negative number, it returns the same value as if it were alled with a rst argument of zero. This an be seen be evaluating the following ode. Here the `)' points to the result of evaluating the ode pre eding it. This was done by positioning the ursor after the ode and typing C-x C-e (eval-last-sexp) in the usual fashion. You an do this if you are reading this in Info inside of GNU Ema s. (% -1 5) ) -1 (setq animals '( ats dogs elephants)) ) ( ats dogs elephants) (nth dr 1 animals) ) (dogs elephants) (nth dr 0 animals) ) ( ats dogs elephants)

252

Appendix B: Handling the Kill Ring (nth dr -1 animals) ) ( ats dogs elephants)

So, if a minus sign or a negative number is passed to yank, the killring-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, \ opyregion-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

then the rst element to whi h kill-ring-yank-pointer points is inserted. This leaves point after the new text. If in the previous yank, point was left before the inserted text, point and mark are now ex hanged so point is again left in front of the newly inserted text. That is all there is to it!

254

Appendix B: Handling the Kill Ring

A Graph with Labelled Axes

255

Appendix C A Graph with Labelled Axes Printed axes help you understand a graph. They onvey s ale. In an earlier hapter (see Chapter 15, \Readying a Graph", page 203), we wrote the ode to print the body of a graph. Here we write the ode for printing and labelling verti al and horizontal axes, along with the body itself. Sin e insertions ll a bu er to the right and below point, the new graph printing fun tion should rst print the Y or verti al axis, then the body of the graph, and nally the X or horizontal axis. This sequen e lays out for us the ontents of the fun tion: 1. Set up ode. 2. Print Y axis. 3. Print body of graph. 4. Print X axis. Here is an example of how a nished graph should look: 10 * * * * ** * *** 5 * ******* * *** ******* ************* *************** 1 - **************** | | | | 1 5 10 15

In this graph, both the verti al and the horizontal axes are labelled with numbers. However, in some graphs, the horizontal axis is time and would be better labelled with months, like this: 5 -

* * ** * ******* ********** ** 1 - ************** | ^ | Jan June Jan

Indeed, with a little thought, we an easily ome up with a variety of verti al and horizontal labelling s hemes. Our task ould be ome ompli ated. But ompli ations breed onfusion. Rather than permit this, it is better hoose a simple labelling s heme for our rst e ort, and to modify or repla e it later.

256

Appendix C: A Graph with Labelled Axes

These onsiderations suggest the following outline for the print-graph fun tion: (defun print-graph (numbers-list) "do umentation..." (let ((height ... ...)) (print-Y-axis height ... ) (graph-body-print numbers-list) (print-X-axis ... )))

We an work on ea h part of the print-graph fun tion de nition in turn.

C.1 The print-graph Varlist In writing the print-graph fun tion, the rst task is to write the varlist in the let expression. (We will leave aside for the moment any thoughts about making the fun tion intera tive or about the ontents of its do umentation string.) The varlist should set several values. Clearly, the top of the label for the verti al axis must be at least the height of the graph, whi h means that we must obtain this information here. Note that the print-graph-body fun tion also requires this information. There is no reason to al ulate the height of the graph in two di erent pla es, so we should hange printgraph-body from the way we de ned it earlier to take advantage of the

al ulation. Similarly, both the fun tion for printing the X axis labels and the printgraph-body fun tion need to learn the value of the width of ea h symbol. We an perform the al ulation here and hange the de nition for printgraph-body from the way we de ned it in the previous hapter. The length of the label for the horizontal axis must be at least as long as the graph. However, this information is used only in the fun tion that prints the horizontal axis, so it does not need to be al ulated here. These thoughts lead us dire tly to the following form for the varlist in the let for print-graph: (let ((height (apply 'max numbers-list)) ; First version. (symbol-width (length graph-blank)))

As we shall see, this expression is not quite right.

C.2 The print-Y-axis Fun tion The job of the print-Y-axis fun tion is to print a label for the verti al axis that looks like this:

Side Trip: Compute a Remainder

257

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 verti 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 essary 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.

C.2.1 Side Trip: Compute a Remainder In Lisp, the fun tion for omputing a remainder is %. The fun tion returns the remainder of its rst argument divided by its se ond argument. As it happens, % is a fun tion in Ema s Lisp that you annot dis over using apropos: you nd nothing if you type M-x apropos hRETi remainder hRETi. The only way to learn of the existen e of % is to read about it in a book su h as this or in the Ema s Lisp sour es. The % fun tion is used in the

ode for rotate-yank-pointer, whi h is des ribed in an appendix. (See Se tion B.1.1, \The Body of rotate-yank-pointer", page 244.) You an try the % fun tion by evaluating the following two expressions: (% 7 5) (% 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 numberslist).) 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-labelspa 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 printgraph 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*.)

C.2.2 Constru t a Y Axis Element When we print the verti al axis, we want to insert strings su h as `5 -' and `10 - ' every ve lines. Moreover, we want the numbers and dashes to line up, so shorter numbers must be padded with leading spa es. If some of the strings use two digit numbers, the strings with single digit numbers must in lude a leading blank spa e before the number. To gure out the length of the number, the length fun tion is used. But the length fun tion works only with a string, not with a number. So the

260

Appendix C: A Graph with Labelled Axes

number has to be onverted from being a number to being a string. This is done with the number-to-string fun tion. For example, (length (number-to-string 35)) ) 2 (length (number-to-string 100)) ) 3

(number-to-string is also alled int-to-string; you will see this alternative name in various sour es.) In addition, in ea h label, ea h number is followed by a string su h as ` - ', whi h we will all the Y-axis-ti marker. This variable is de ned with defvar: (defvar Y-axis-ti " - " "String that follows number in a Y axis label.")

The length of the Y label is the sum of the length of the Y axis ti mark and the length of the number of the top of the graph. (length ( on at (number-to-string height) Y-axis-ti )))

This value will be al ulated by the print-graph fun tion in its varlist as full-Y-label-width and passed on. (Note that we did not think to in lude

this in the varlist when we rst proposed it.) To make a omplete verti al axis label, a ti mark is on atenated with a number; and the two together may be pre eded by one or more spa es depending on how long the number is. The label onsists of three parts: the (optional) leading spa es, the number, and the ti mark. The fun tion is passed the value of the number for the spe i row, and the value of the width of the top line, whi h is al ulated (just on e) by print-graph. (defun Y-axis-element (number full-Y-label-width) "Constru t a NUMBERed label element. A numbered element looks like this ` 5 - ', and is padded as needed so all line up with the element for the largest number." (let* ((leading-spa es (- full-Y-label-width (length ( on at (number-to-string number) Y-axis-ti ))))) ( on at (make-string leading-spa es ? ) (number-to-string number) Y-axis-ti )))

The Y-axis-element fun tion on atenates together the leading spa es, if any; the number, as a string; and the ti mark.

The Not Quite Final Version of print-Y-axis

261

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.

C.2.3 Create a Y Axis Column The pre eding fun tions provide all the tools needed to onstru t a fun tion that generates a list of numbered and blank strings to insert as the label for the verti al axis: (defun Y-axis- olumn (height width-of-label) "Constru t list of Y axis labels and blank strings. For HEIGHT of line above base and WIDTH-OF-LABEL." (let (Y-axis) (while (> height 1) (if (zerop (% height Y-axis-label-spa ing)) ;; Insert label. (setq Y-axis ( ons (Y-axis-element height width-of-label) Y-axis)) ;; Else, insert blanks. (setq Y-axis ( ons (make-string width-of-label ? ) Y-axis))) (setq height (1- height))) ;; Insert base line. (setq Y-axis ( ons (Y-axis-element 1 width-of-label) Y-axis)) (nreverse Y-axis)))

In this fun tion, we start with the value of height and repetitively subtra t one from its value. After ea h subtra tion, we test to see whether the value is an integral multiple of the Y-axis-label-spa ing. If it is, we onstru t a numbered label using the Y-axis-element fun tion; if not,

262

Appendix C: A Graph with Labelled Axes

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.

C.2.4 The Not Quite Final Version of print-Y-axis The list onstru ted by the Y-axis- olumn fun tion is passed to the print-Y-axis fun tion, whi h inserts the list as a olumn. (defun print-Y-axis (height full-Y-label-width) "Insert Y axis using HEIGHT and FULL-Y-LABEL-WIDTH. Height must be the maximum height of the graph. Full width is the width of the highest label element." ;; Value of height and full-Y-label-width ;; are passed by `print-graph'. (let ((start (point))) (insert-re tangle (Y-axis- olumn height full-Y-label-width)) ;; Pla e point ready for inserting graph. (goto- har start) ;; Move point forward by value of full-Y-label-width (forward- har full-Y-label-width)))

The print-Y-axis uses the insert-re tangle fun tion to insert the Y axis labels reated by the Y-axis- olumn fun tion. In addition, it pla es point at the orre t position for printing the body of the graph. You an test print-Y-axis: 1. Install Y-axis-label-spa ing Y-axis-ti Y-axis-element Y-axis- olumn print-Y-axis

2. Copy the following expression: (print-Y-axis 12 5)

3. Swit h to the `*s rat h*' bu er and pla e the ursor where you want the axis labels 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 expression. Ema s will print labels verti ally, the top one being `10 - '. (The printgraph fun tion will pass the value of height-of-top-line, whi h in this

ase would end up as 15.)

X Axis Ti Marks

263

C.3 The print-X-axis Fun tion X axis labels are mu h like Y axis labels, ex ept that the ti s are on a line above the numbers. Labels should look like this: | 1

| 5

| 10

| 15

The rst ti is under the rst olumn of the graph and is pre eded by several blank spa es. These spa es provide room in rows above for the Y axis labels. The se ond, third, fourth, and subsequent ti s are all spa ed equally, a

ording to the value of X-axis-label-spa ing. The se ond row of the X axis onsists of numbers, pre eded by several blank spa es and also separated a

ording to the value of the variable Xaxis-label-spa ing. The value of the variable X-axis-label-spa ing should itself be measured in units of symbol-width, sin e you may want to hange the width of the symbols that you are using to print the body of the graph without

hanging the ways the graph is labelled. The print-X-axis fun tion is onstru ted in more or less the same fashion as the print-Y-axis fun tion ex ept that it has two lines: the line of ti marks and the numbers. We will write a separate fun tion to print ea h line and then ombine them within the print-X-axis fun tion. This is a three step pro ess: 1. Write a fun tion to print the X axis ti marks, print-X-axis-ti -line. 2. Write a fun tion to print the X numbers, print-X-axis-numberedline. 3. Write a fun tion to print both lines, the print-X-axis fun tion, using print-X-axis-ti -line and print-X-axis-numbered-line.

C.3.1 X Axis Ti Marks The rst fun tion should print the X axis ti marks. We must spe ify the ti marks themselves and their spa ing: (defvar X-axis-label-spa ing (if (boundp 'graph-blank) (* 5 (length graph-blank)) 5) "Number of units from one X axis label to next.")

(Note that the value of graph-blank is set by another defvar. The boundp predi ate he ks whether it has already been set; boundp returns nil if it has not. If graph-blank were unbound and we did not use

this onditional onstru tion, in GNU Ema s 21, we would enter the debugger and see an error message saying `Debugger entered--Lisp error: (void-variable graph-blank)'.)

264

Appendix C: A Graph with Labelled Axes

Here is the defvar for X-axis-ti -symbol: (defvar X-axis-ti -symbol "|" "String to insert to point to a olumn in X axis.")

The goal is to make a line that looks like this: |

|

|

|

The rst ti is indented so that it is under the rst olumn, whi h is indented to provide spa e for the Y axis labels. A ti element onsists of the blank spa es that stret h from one ti to the next plus a ti symbol. The number of blanks is determined by the width of the ti symbol and the X-axis-label-spa ing. The ode looks like this: ;;; X-axis-ti -element ... ( 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) ...

Next, we determine how many blanks are needed to indent the rst ti mark to the rst olumn of the graph. This uses the value of full-Y-labelwidth passed it by the print-graph fun tion. The ode to make X-axis-leading-spa es looks like this: ;; X-axis-leading-spa es ... (make-string full-Y-label-width ? ) ...

We also need to determine the length of the horizontal axis, whi h is the length of the numbers list, and the number of ti s in the horizontal axis: ;; X-length ... (length numbers-list) ;; ti -width ... (* symbol-width X-axis-label-spa ing)

X Axis Ti Marks

265

;; 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))))

The line of numbers is equally straightforward: First, we reate a numbered element with blank spa es before ea h number: (defun X-axis-element (number) "Constru t a numbered X axis element." (let ((leading-spa es (- (* symbol-width X-axis-label-spa ing) (length (number-to-string number))))) ( on at (make-string leading-spa es ? ) (number-to-string number))))

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-axisti -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

You an test print-X-axis: 1. Install X-axis-ti -symbol, X-axis-label-spa ing, print-X-axisti -line, as well as X-axis-element, print-X-axis-numbered-line, and print-X-axis. 2. Copy the following expression: (progn (let ((full-Y-label-width 5) (symbol-width 1)) (print-X-axis '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))))

3. Swit h to the `*s rat h*' bu er and pla e the ursor where you want the axis labels to start. 4. Type M-: (eval-expression). 5. Yank the test expression into the minibu er with C-y (yank). 6. Press hRETi to evaluate the expression. Ema s will print the horizontal axis like this: | 1

| 5

| 10

| 15

| 20

C.4 Printing the Whole Graph Now we are nearly ready to print the whole graph. The fun tion to print the graph with the proper labels follows the outline we reated earlier (see Appendix C, \A Graph with Labelled Axes", page 255), but with additions. Here is the outline: (defun print-graph (numbers-list) "do umentation..." (let ((height ... ...)) (print-Y-axis height ... ) (graph-body-print numbers-list) (print-X-axis ... )))

The nal version is di erent from what we planned in two ways: rst, it

ontains additional values al ulated on e in the varlist; se ond, it arries an option to spe ify the labels' in rement per row. This latter feature turns out to be essential; otherwise, a graph may have more rows than t on a display or on a sheet of paper.

268

Appendix C: A Graph with Labelled Axes

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: ;;; Final version. (defun Y-axis- olumn (height width-of-label &optional verti al-step) "Constru t list of labels for Y axis. HEIGHT is maximum height of graph. WIDTH-OF-LABEL is maximum width of label. VERTICAL-STEP, an option, is a positive integer that spe ifies how mu h a Y axis label in rements for ea h line. For example, a step of 5 means that ea h line is five units of the graph." (let (Y-axis (number-per-line (or verti al-step 1))) (while (> height 1) (if (zerop (% height Y-axis-label-spa ing)) ;; Insert label. (setq Y-axis ( ons (Y-axis-element (* height number-per-line) width-of-label) Y-axis)) ;; Else, insert blanks. (setq Y-axis ( ons (make-string width-of-label ? ) Y-axis))) (setq height (1- height))) ;; Insert base line. (setq Y-axis ( ons (Y-axis-element (or verti al-step 1) width-of-label) Y-axis)) (nreverse Y-axis)))

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 ;;; Final version. (defun graph-body-print (numbers-list height symbol-width) "Print a bar graph of the NUMBERS-LIST. The numbers-list onsists of the Y-axis values. HEIGHT is maximum height of graph. SYMBOL-WIDTH is number of ea h olumn." (let (from-position) (while numbers-list (setq from-position (point)) (insert-re tangle ( olumn-of-graph height ( ar numbers-list))) (goto- har from-position) (forward- har symbol-width) ;; Draw graph olumn by olumn. (sit-for 0) (setq numbers-list ( dr numbers-list))) ;; Pla e point for X axis labels. (forward-line height) (insert "\n")))

Finally, the ode for the print-graph fun tion: ;;; Final version. (defun print-graph (numbers-list &optional verti al-step) "Print labelled bar graph of the NUMBERS-LIST. The numbers-list onsists of the Y-axis values. Optionally, VERTICAL-STEP, a positive integer, spe ifies how mu h a Y axis label in rements for ea h line. For example, a step of 5 means that ea h row is five units." (let* ((symbol-width (length graph-blank)) ;; height is both the largest number ;; and the number with the most digits. (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))) (verti al-step (or verti al-step 1)) (full-Y-label-width (length

269

270

Appendix C: A Graph with Labelled Axes ( 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)))

C.4.1 Testing print-graph We an test the print-graph fun tion with a short list of numbers: 1. Install the nal versions of Y-axis- olumn, graph-body-print, and print-graph (in addition to the rest of the ode.) 2. Copy the following expression: (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1))

3. Swit h to the `*s rat h*' bu er and pla e the ursor where you want the axis labels to start. 4. Type M-: (eval-expression). 5. Yank the test expression into the minibu er with C-y (yank). 6. Press hRETi to evaluate the expression. Ema s will print a graph that looks like this: 10 -

* ** * 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

The graph looks like this: 20 -

* ** * 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.)

C.4.2 Graphing Numbers of Words and Symbols Now for the graph for whi h all this ode was written: a graph that shows how many fun tion de nitions ontain fewer than 10 words and symbols, how many ontain between 10 and 19 words and symbols, how many ontain between 20 and 29 words and symbols, and so on. This is a multi-step pro ess. First make sure you have loaded all the requisite ode. It is a good idea to reset the value of top-of-ranges in ase you have set it to some di erent value. You an evaluate the following: (setq '(10 60 110 160 210 260

top-of-ranges 20 30 40 50 70 80 90 100 120 130 140 150 170 180 190 200 220 230 240 250 270 280 290 300)

Next reate a list of the number of words and symbols in ea h range.

272

Appendix C: A Graph with Labelled Axes

Evaluate the following: (setq list-for-graph (defuns-per-range (sort (re ursive-lengths-list-many-files (dire tory-files "/usr/lo al/ema s/lisp" t ".+el$")) '<) top-of-ranges))

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-forgraph 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 nitions 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))

C.4.3 A lambda Expression: Useful Anonymity lambda is the symbol for an anonymous fun tion, a fun tion without a name. Every time you use an anonymous fun tion, you need to in lude its whole body.

The map ar Fun tion

273

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 21. Similarly, we an write: ((lambda (number) (* 7 number)) 3)

anonymous function

argument

If we want to divide 100 by 50, we an write: ((lambda (arg) (/ arg 50)) 100)

anonymous 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

C.4.4 The map ar Fun tion map ar is a fun tion that alls its rst argument with ea h element of its se ond argument, in turn. The se ond argument must be a sequen e. The `map' part of the name omes from the mathemati al phrase, `mapping over a domain', meaning to apply a fun tion to ea h of the elements in a domain. The mathemati al phrase is based on the metaphor of a surveyor walking, one step at a time, over an area he is mapping. And ` ar', of ourse,

omes from the Lisp notion of the rst of a list. For example, (map ar '1+ '(2 4 6)) ) (3 5 7)

The fun tion 1+ whi h adds one to its argument, is exe uted on ea h element of the list, and a new list is returned. Contrast this with apply, whi h applies its rst argument to all the remaining. (See Chapter 15, \Readying a Graph", page 203, for a explanation of apply.) In the de nition of one-fiftieth, the rst argument is the anonymous fun tion: (lambda (arg) (/ arg 50))

and the se ond argument is full-range, whi h will be bound to list-forgraph. The whole expression looks like this: (map ar '(lambda (arg) (/ arg 50)) full-range))

See se tion \Mapping Fun tions" in The GNU Ema s Lisp Referen e Manual, for more about map ar. Using the one-fiftieth fun tion, we an generate a list in whi h ea h element is one- ftieth the size of the orresponding element in list-forgraph. (setq fiftieth-list-for-graph (one-fiftieth list-for-graph))

The resulting list looks like this:

(10 20 19 15 11 9 6 5 4 3 3 2 2 1 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 4)

This, we are almost ready to print! (We also noti e the loss of information: many of the higher ranges are 0, meaning that fewer than 50 defuns had that many words or symbols|but not ne essarily meaning that none had that many words or symbols.)

C.4.5 Another Bug . . . Most Insidious I said `almost ready to print'! Of ourse, there is a bug in the printgraph fun tion . . . It has a verti al-step option, but not a horizontal-

Another Bug . . . Most Insidious

275

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-Xaxis 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

C.4.6 The Printed Graph When made and installed, you an all the print-graph ommand like this: (print-graph fiftieth-list-for-graph 50 10)

Here is the graph: 1000 -

750

500

250

50

* ** ** ** ** - *** *** *** *** **** - ***** ****** ****** ****** ******* - ******** ********* *********** ************* - ***************** * | | | | | 10 50 100 150 200

* * * * | 250

| 300

| 350

The largest group of fun tions ontain 10 { 19 words and symbols ea h.

278

Appendix C: A Graph with Labelled Axes

GNU Free Do umentation Li ense

279

Appendix D GNU Free Do umentation Li ense Version 1.1, Mar h 2000

2000 Free Software Foundation, In . Copyright 59 Temple Pla e, Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to opy and distribute verbatim opies of this li ense do ument, but hanging it is not allowed. 0. PREAMBLE The purpose of this Li ense is to make a manual, textbook, or other written do ument free in the sense of freedom: to assure everyone the e e tive freedom to opy and redistribute it, with or without modifying it, either ommer ially or non ommer ially. Se ondarily, this Li ense preserves for the author and publisher a way to get redit for their work, while not being onsidered responsible for modi ations made by others. This Li ense is a kind of \ opyleft", whi h means that derivative works of the do ument must themselves be free in the same sense. It omplements the GNU General Publi Li ense, whi h is a opyleft li ense designed for free software. We have designed this Li ense in order to use it for manuals for free software, be ause free software needs free do umentation: a free program should ome with manuals providing the same freedoms that the software does. But this Li ense is not limited to software manuals; it an be used for any textual work, regardless of subje t matter or whether it is published as a printed book. We re ommend this Li ense prin ipally for works whose purpose is instru tion or referen e. 1. APPLICABILITY AND DEFINITIONS This Li ense applies to any manual or other work that ontains a noti e pla ed by the opyright holder saying it an be distributed under the terms of this Li ense. The \Do ument", below, refers to any su h manual or work. Any member of the publi is a li ensee, and is addressed as \you". A \Modi ed Version" of the Do ument means any work ontaining the Do ument or a portion of it, either opied verbatim, or with modi ations and/or translated into another language. A \Se ondary Se tion" is a named appendix or a front-matter se tion of the Do ument that deals ex lusively with the relationship of the publishers or authors of the Do ument to the Do ument's overall subje t (or to related matters) and ontains nothing that ould fall dire tly within that overall subje t. (For example, if the Do ument is in part a textbook of mathemati s, a Se ondary Se tion may not explain any

280

Appendix D: GNU Free Do umentation Li ense

mathemati s.) The relationship ould be a matter of histori al onne tion with the subje t or with related matters, or of legal, ommer ial, philosophi al, ethi al or politi al position regarding them. The \Invariant Se tions" are ertain Se ondary Se tions whose titles are designated, as being those of Invariant Se tions, in the noti e that says that the Do ument is released under this Li ense. The \Cover Texts" are ertain short passages of text that are listed, as Front-Cover Texts or Ba k-Cover Texts, in the noti e that says that the Do ument is released under this Li ense. A \Transparent" opy of the Do ument means a ma hine-readable opy, represented in a format whose spe i ation is available to the general publi , whose ontents an be viewed and edited dire tly and straightforwardly with generi text editors or (for images omposed of pixels) generi paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automati translation to a variety of formats suitable for input to text formatters. A opy made in an otherwise Transparent le format whose markup has been designed to thwart or dis ourage subsequent modi ation by readers is not Transparent. A opy that is not \Transparent" is alled \Opaque". Examples of suitable formats for Transparent opies in lude plain as ii without markup, Texinfo input format, LaTEX input format, sgml or xml using a publi ly available dtd, and standard- onforming simple html designed for human modi ation. Opaque formats in lude PostS ript, pdf, proprietary formats that an be read and edited only by proprietary word pro essors, sgml or xml for whi h the dtd and/or pro essing tools are not generally available, and the ma hine-generated html produ ed by some word pro essors for output purposes only. The \Title Page" means, for a printed book, the title page itself, plus su h following pages as are needed to hold, legibly, the material this Li ense requires to appear in the title page. For works in formats whi h do not have any title page as su h, \Title Page" means the text near the most prominent appearan e of the work's title, pre eding the beginning of the body of the text. 2. VERBATIM COPYING You may opy and distribute the Do ument in any medium, either ommer ially or non ommer ially, provided that this Li ense, the opyright noti es, and the li ense noti e saying this Li ense applies to the Do ument are reprodu ed in all opies, and that you add no other onditions whatsoever to those of this Li ense. You may not use te hni al measures to obstru t or ontrol the reading or further opying of the opies you make or distribute. However, you may a

ept ompensation in ex hange for opies. If you distribute a large enough number of opies you must also follow the onditions in se tion 3.

GNU Free Do umentation Li ense

281

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 Transparent 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 omplete 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 Transparent 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 B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modi ations in the Modi ed Version, together with at least ve of the prin ipal authors of the Do ument (all of its prin ipal authors, if it has less than ve). C. State on the Title page the name of the publisher of the Modi ed Version, as the publisher. D. Preserve all the opyright noti es of the Do ument. E. Add an appropriate opyright noti e for your modi ations adja ent to the other opyright noti es. F. In lude, immediately after the opyright noti es, a li ense noti e giving the publi permission to use the Modi ed Version under the terms of this Li ense, in the form shown in the Addendum below. G. Preserve in that li ense noti e the full lists of Invariant Se tions and required Cover Texts given in the Do ument's li ense noti e. H. In lude an unaltered opy of this Li ense. I. Preserve the se tion entitled \History", and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modi ed Version as given on the Title Page. If there is no se tion entitled \History" in the Do ument, reate one stating the title, year, authors, and publisher of the Do ument as given on its Title Page, then add an item des ribing the Modi ed Version as stated in the previous senten e. J. Preserve the network lo ation, if any, given in the Do ument for publi a

ess to a Transparent opy of the Do ument, and likewise the network lo ations given in the Do ument for previous versions it was based on. These may be pla ed in the \History" se tion. You may omit a network lo ation for a work that was published at least four years before the Do ument itself, or if the original publisher of the version it refers to gives permission. K. In any se tion entitled \A knowledgments" or \Dedi ations", preserve the se tion's title, and preserve in the se tion all the substan e and tone of ea h of the ontributor a knowledgments and/or dedi ations given therein. L. Preserve all the Invariant Se tions of the Do ument, unaltered in their text and in their titles. Se tion numbers or the equivalent are not onsidered part of the se tion titles. M. Delete any se tion entitled \Endorsements". Su h a se tion may not be in luded in the Modi ed Version. N. Do not retitle any existing se tion as \Endorsements" or to on i t in title with any Invariant Se tion. If the Modi ed Version in ludes new front-matter se tions or appendi es that qualify as Se ondary Se tions and ontain no material opied from the Do ument, you may at your option designate some or all of these

GNU Free Do umentation Li ense

283

se tions as invariant. To do this, add their titles to the list of Invariant Se tions in the Modi ed Version's li ense noti e. These titles must be distin t from any other se tion titles. You may add a se tion entitled \Endorsements", provided it ontains nothing but endorsements of your Modi ed Version by various parties| for example, statements of peer review or that the text has been approved by an organization as the authoritative de nition of a standard. You may add a passage of up to ve words as a Front-Cover Text, and a passage of up to 25 words as a Ba k-Cover Text, to the end of the list of Cover Texts in the Modi ed Version. Only one passage of Front-Cover Text and one of Ba k-Cover Text may be added by (or through arrangements made by) any one entity. If the Do ument already in ludes a over text for the same over, previously added by you or by arrangement made by the same entity you are a ting on behalf of, you may not add another; but you may repla e the old one, on expli it permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Do ument do not by this Li ense give permission to use their names for publi ity for or to assert or imply endorsement of any Modi ed Version. 5. COMBINING DOCUMENTS You may ombine the Do ument with other do uments released under this Li ense, under the terms de ned in se tion 4 above for modi ed versions, provided that you in lude in the ombination all of the Invariant Se tions of all of the original do uments, unmodi ed, and list them all as Invariant Se tions of your ombined work in its li ense noti e. The ombined work need only ontain one opy of this Li ense, and multiple identi al Invariant Se tions may be repla ed with a single opy. If there are multiple Invariant Se tions with the same name but di erent

ontents, make the title of ea h su h se tion unique by adding at the end of it, in parentheses, the name of the original author or publisher of that se tion if known, or else a unique number. Make the same adjustment to the se tion titles in the list of Invariant Se tions in the li ense noti e of the ombined work. In the ombination, you must ombine any se tions entitled \History" in the various original do uments, forming one se tion entitled \History"; likewise ombine any se tions entitled \A knowledgments", and any se tions entitled \Dedi ations". You must delete all se tions entitled \Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a olle tion onsisting of the Do ument and other do uments released under this Li ense, and repla e the individual opies of this Li ense in the various do uments with a single opy that is in luded in the olle tion, provided that you follow the rules of this Li ense for verbatim opying of ea h of the do uments in all other respe ts.

284

7.

8.

9.

10.

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. 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 Version 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. 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. 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, parties 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. 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 %

% (remainder fun tion) . . . . . . . . . . . . . . 258

(

(debug) in ode . . . . . . . . . . . . . . . . . . . . 235

*

* (multipli ation) . . . . . . . . . . . . . . . . . . . . 31 * for read-only bu er . . . . . . . . . . . . . . . . . 65 `*s rat h*' bu er . . . . . . . . . . . . . . . . . . 123

.

`.ema s' le . . . . . . . . . . . . . . . . . . . . . . . . 213 `.ema s' le, beginning of . . . . . . . . . . . 216

/

/ (division) . . . . . . . . . . . . . . . . . . . . . . . . . . 72

>

> (greater than) . . . . . . . . . . . . . . . . . . . . 40

<

<= (less than or equal) . . . . . . . . . . . . . . 127

A

A

umulate, type of re ursive pattern ...............................

142

add-hook . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 and . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108, 156 and, introdu ed . . . . . . . . . . . . . . . . . . . . 108

Anonymous fun tion . . . . . . . . . . . . . . . . 272 append-to-buffer . . . . . . . . . . . . . . . . . . . 56 apply . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 apropos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Argument as lo al variable . . . . . . . . . . 131 `argument' de ned . . . . . . . . . . . . . . . . . . . 12 `argument list' de ned . . . . . . . . . . . . . . 30 Argument, wrong type of . . . . . . . . . . . . . 14

Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Arguments' data types . . . . . . . . . . . . . . . 13 Arguments, variable number of . . . . . . . . 14 Asterisk for read-only bu er . . . . . . . . . . 65 Auto Fill mode turned on . . . . . . . . . . . 218 autoload . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 Automati mode sele tion . . . . . . . . . . . 218 Axis, print horizontal . . . . . . . . . . . . . . . 263 Axis, print verti al . . . . . . . . . . . . . . . . . . 256

B

beginning-of-buffer . . . . . . . . . . . . . . . . 69 `bind' de ned . . . . . . . . . . . . . . . . . . . . . . . 17 `body' de ned . . . . . . . . . . . . . . . . . . . . . . . 30

Body of graph . . . . . . . . . . . . . . . . . . . . . . 203 Bu er size . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Bu er, history of word . . . . . . . . . . . . . . . 24 buffer-file-name . . . . . . . . . . . . . . . . . . . 23 buffer-menu, bound to key . . . . . . . . . 221 buffer-name . . . . . . . . . . . . . . . . . . . . . . . . 23 Bug, most insidious type . . . . . . . . . . . . 274 Building robots . . . . . . . . . . . . . . . . . . . . . 134 Building Tags in the Ema s sour es . . 164 Byte ompiling . . . . . . . . . . . . . . . . . . . . . . . 8

C

C language primitives . . . . . . . . . . . . . . . . 29 C, a digression into . . . . . . . . . . . . . . . . . . 98 ` all' de ned . . . . . . . . . . . . . . . . . . . . . . . 27

an el-debug-on-entry . . . . . . . . . . . . . 234

ar, introdu ed . . . . . . . . . . . . . . . . . . . . . 81

dr, introdu ed . . . . . . . . . . . . . . . . . . . . . 81 Changing a fun tion de nition . . . . . . . . 32 Chest of Drawers, metaphor for a symbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 Clipping text . . . . . . . . . . . . . . . . . . . . . . . . 89 Code installation . . . . . . . . . . . . . . . . . . . . 36 ` ommand' de ned . . . . . . . . . . . . . . . . . . . . 23 Comments in Lisp ode . . . . . . . . . . . . . . 32 Common Lisp . . . . . . . . . . . . . . . . . . . . . . . xiii

ompare-windows . . . . . . . . . . . . . . . . . . . 220

on at . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

ond . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

ondition- ase . . . . . . . . . . . . . . . . . . . . . 95

288 Conditional 'twixt two versions of Ema s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Conditional with if . . . . . . . . . . . . . . . . . . 39

ons, example . . . . . . . . . . . . . . . . . . . . . . 107

ons, introdu ed . . . . . . . . . . . . . . . . . . . . 83

opy-region-as-kill . . . . . . . . . . . . . . . 102

opy-to-buffer . . . . . . . . . . . . . . . . . . . . . 63 Count words re ursively . . . . . . . . . . . . . 173

ount-words-in-defun . . . . . . . . . . . . . . 185

ount-words-region . . . . . . . . . . . . . . . . 167 Counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Counting words in a defun . . . . . . 181, 183

urrent-buffer . . . . . . . . . . . . . . . . . . . . . 25 Customizing your `.ema s' le . . . . . . . 213 Cutting and storing text . . . . . . . . . . . . . . 89

D

Data types . . . . . . . . . . . . . . . . . . . . . . . . . . 13

debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 debug-on-entry . . . . . . . . . . . . . . . . . . . . 232 debug-on-quit . . . . . . . . . . . . . . . . . . . . . 234

debugging . . . . . . . . . . . . . . . . . . . . . . . . . . 231 default-mode-line-format . . . . . . . . . 228 `default.el' init le . . . . . . . . . . . . . . . . 213 def ustom . . . . . . . . . . . . . . . . . . . . . . . . . 214 Deferment in re ursion . . . . . . . . . . . . . . 143 Defermentless solution . . . . . . . . . . . . . . 145 De nition installation . . . . . . . . . . . . . . . . 31 De nition writing . . . . . . . . . . . . . . . . . . . . 29 De nition, how to hange . . . . . . . . . . . . . 32 defun . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 defvar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 defvar for a user ustomizable variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 defvar with an asterisk . . . . . . . . . . . . . 101 delete-and-extra t-region . . . . . . 96, 98 Deleting text . . . . . . . . . . . . . . . . . . . . . . . . 89 des ribe-fun tion . . . . . . . . . . . . . . . . . . 53 des ribe-fun tion, introdu ed . . . . . . 51 Digression into C . . . . . . . . . . . . . . . . . . . . 98 dire tory-files . . . . . . . . . . . . . . . . . . . 194 Division . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 dolist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 dotimes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 Drawers, Chest of, metaphor for a symbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 Dupli ated words fun tion . . . . . . . . . . . 241

Index

E

edebug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 edit-options . . . . . . . . . . . . . . . . . . . . . . 101

Else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Ema s version, hoosing . . . . . . . . . . . . . 225 `empty list' de ned . . . . . . . . . . . . . . . . . . 2 `empty string' de ned . . . . . . . . . . . . . . . 48 eobp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 eq . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 eq (example of use) . . . . . . . . . . . . . . . . . 104 equal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Erasing text . . . . . . . . . . . . . . . . . . . . . . . . . 89 error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 Error for symbol without fun tion . . . . . 11 Error for symbol without value . . . . . . . 11 Error message generation . . . . . . . . . . . . . . 4 etags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 `evaluate' de ned . . . . . . . . . . . . . . . . . . . . 4 Evaluating inner lists . . . . . . . . . . . . . . . . . . 9 Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Evaluation pra ti e . . . . . . . . . . . . . . . . . . 23 Every, type of re ursive pattern . . . . . . 141 Example variable, fill- olumn . . . . . . . 10 `expression' de ned . . . . . . . . . . . . . . . . . . 2

F

Falsehood and truth in Ema s Lisp . . . . 43 FDL, GNU Free Do umentation Li ense . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 files-in-below-dire tory . . . . . . . . . 194 fill- olumn, an example variable . . . . 10 Find a File . . . . . . . . . . . . . . . . . . . . . . . . . 187 Find fun tion do umentation . . . . . . . . . 51 Find sour e of fun tion . . . . . . . . . . . . . . . 51 find-tags . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Flowers in a eld . . . . . . . . . . . . . . . . . . . . . 1 Fo using attention (narrowing) . . . . . . . 77 `form' de ned . . . . . . . . . . . . . . . . . . . . . . . . . 2 Formatting onvention . . . . . . . . . . . . . . . 58 Formatting help . . . . . . . . . . . . . . . . . . . . . . 3 forward-paragraph . . . . . . . . . . . . . . . . . 155 forward-senten e . . . . . . . . . . . . . . . . . . 151 `fun tion' de ned . . . . . . . . . . . . . . . . . . 5, 6 `fun tion definition' de ned . . . . . . . . 29 Fun tion de nition installation . . . . . . . . 31 Fun tion de nition writing . . . . . . . . . . . 29 Fun tion de nition, how to hange . . . . 32 Fun tions, primitive . . . . . . . . . . . . . . . . . . 29

Index

G

Generate an error message . . . . . . . . . . . . . 4 Getting a bu er . . . . . . . . . . . . . . . . . . . . . 25 Global set key . . . . . . . . . . . . . . . . . . . . . . 220 global-set-key . . . . . . . . . . . . . . . . . . . . 220 global-unset-key . . . . . . . . . . . . . . . . . . 221 Graph prototype . . . . . . . . . . . . . . . . . . . . 203 Graph, printing all . . . . . . . . . . . . . . . . . . 267 graph-body-print . . . . . . . . . . . . . . . . . . 208 graph-body-print Final version. . . . . . 268

H

Handling the kill ring . . . . . . . . . . . . . . . 243 Help typing lists . . . . . . . . . . . . . . . . . . . . . . 3 Horizontal axis printing . . . . . . . . . . . . . 263

I

if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 `if-part' de ned . . . . . . . . . . . . . . . . . . . . 40 indent-tabs-mode . . . . . . . . . . . . . . . . . . 219

Indentation for formatting . . . . . . . . . . . . 58 Initialization le . . . . . . . . . . . . . . . . . . . . 213 Initializing a variable . . . . . . . . . . . . . . . . 100 Inner list evaluation . . . . . . . . . . . . . . . . . . . 9 insert-buffer . . . . . . . . . . . . . . . . . . . . . . 64 insert-buffer-substring . . . . . . . . . . . 56 Insidious type of bug . . . . . . . . . . . . . . . . 274 Install a Fun tion De nition . . . . . . . . . . 31 Install ode permanently . . . . . . . . . . . . . 36 intera tive . . . . . . . . . . . . . . . . . . . . . . . . 33 `intera tive fun tion' de ned . . . . . . . 23 Intera tive fun tions . . . . . . . . . . . . . . . . . 33 Intera tive options . . . . . . . . . . . . . . . . . . . 35 intera tive, example use of . . . . . . . . . 65 Interpreter, Lisp, explained . . . . . . . . . . . . 4 Interpreter, what it does . . . . . . . . . . . . . . . 7

K

Keep, type of re ursive pattern . . . . . . 143 Key setting globally . . . . . . . . . . . . . . . . . 220 Key unbinding . . . . . . . . . . . . . . . . . . . . . . 221 Keymaps . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Kill ring handling . . . . . . . . . . . . . . . . . . . 243 Kill ring overview . . . . . . . . . . . . . . . . . . . 117 kill-append . . . . . . . . . . . . . . . . . . . . . . . 104

289 kill-new . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 kill-region . . . . . . . . . . . . . . . . . . . . . . . . 94

Killing text . . . . . . . . . . . . . . . . . . . . . . . . . . 89

L

lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 lengths-list-file . . . . . . . . . . . . . . . . . 188 lengths-list-many-files . . . . . . . . . . 190 let . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 let expression sample . . . . . . . . . . . . . . . . 38 let expression, parts of . . . . . . . . . . . . . . 37 let variables uninitialized . . . . . . . . . . . . 39

Library, as term for ` le' . . . . . . . . . . . . . 52

line-to-top-of-window . . . . . . . . . . . . . 224

Lisp Atoms . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Lisp history . . . . . . . . . . . . . . . . . . . . . . . . xiii Lisp interpreter, explained . . . . . . . . . . . . . 4 Lisp interpreter, what it does . . . . . . . . . . 7 Lisp Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Lisp ma ro . . . . . . . . . . . . . . . . . . . . . . . . . . 97 list-buffers, rebound . . . . . . . . . . . . . 221 Lists in a omputer . . . . . . . . . . . . . . . . . 113 load-library . . . . . . . . . . . . . . . . . . . . . . 223 load-path . . . . . . . . . . . . . . . . . . . . . . . . . 223 Loading les . . . . . . . . . . . . . . . . . . . . . . . . 222 `lo al variable' de ned . . . . . . . . . . . . . 37 Lo al variables list, per-bu er, . . . . . . . 218 Lo ation of point . . . . . . . . . . . . . . . . . . . . 27 looking-at . . . . . . . . . . . . . . . . . . . . . . . . 159 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Loops and re ursion . . . . . . . . . . . . . . . . . 121

M

Ma lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii Ma ro, lisp . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Mail aliases . . . . . . . . . . . . . . . . . . . . . . . . 219 make tags . . . . . . . . . . . . . . . . . . . . . . . . . . 164 make-string . . . . . . . . . . . . . . . . . . . . . . . 261 map ar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 mark . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 mark-whole-buffer . . . . . . . . . . . . . . . . . . 54 mat h-beginning . . . . . . . . . . . . . . . . . . . 161 max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 min . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Mode line format . . . . . . . . . . . . . . . . . . . 228

290 Mode sele tion, automati . . . . . . . . . . . 218 Motion by senten e and paragraph . . . 149

N

Narrowing . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 `narrowing' de ned . . . . . . . . . . . . . . . . . . 28 nil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 nil, history of word . . . . . . . . . . . . . . . . . . 24 No deferment solution . . . . . . . . . . . . . . . 145 nreverse . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 nth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 nth dr . . . . . . . . . . . . . . . . . . . . . . . . . 85, 102 nth dr, example . . . . . . . . . . . . . . . . . . . 107 number-to-string . . . . . . . . . . . . . . . . . . 259

O

o

ur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 optional . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

Optional arguments . . . . . . . . . . . . . . . . . . 70 Options for intera tive . . . . . . . . . . . . . 35 or . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 other-buffer . . . . . . . . . . . . . . . . . . . . . . . 25

P

Paragraphs, movement by . . . . . . . . . . . 149 Parts of a Re ursive De nition . . . . . . . 135 Parts of let expression . . . . . . . . . . . . . . . 37 Passing information to fun tions . . . . . . 12 Pasting text . . . . . . . . . . . . . . . . . . . . . . . . 117 Patterns, sear hing for . . . . . . . . . . . . . . 149 Per-bu er, lo al variables list . . . . . . . . 218 Permanent ode installation . . . . . . . . . . 36 point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 `point' de ned . . . . . . . . . . . . . . . . . . . . . . 27 Point lo ation . . . . . . . . . . . . . . . . . . . . . . . 27 Point, mark, bu er preservation . . . . . . . 44 Pra ti ing evaluation . . . . . . . . . . . . . . . . . 23 Preserving point, mark, and bu er . . . . 44 Primitive fun tions . . . . . . . . . . . . . . . . . . . 29 Primitives written in C . . . . . . . . . . . . . . . 29 Print horizontal axis . . . . . . . . . . . . . . . . 263 Print verti al axis . . . . . . . . . . . . . . . . . . . 256 print-elements-of-list . . . . . . . . . . . 123 print-elements-re ursively . . . . . . . 136 print-graph Final version. . . . . . . . . . . 269 print-graph varlist . . . . . . . . . . . . . . . . . 256

Index 266 265 265 262 Printing the whole graph . . . . . . . . . . . . 267 prog1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 progn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Program, running one . . . . . . . . . . . . . . . . . 4 Prototype graph . . . . . . . . . . . . . . . . . . . . 203 print-X-axis . . . . . . . . . . . . . . . . . . . . . . print-X-axis-numbered-line . . . . . . . print-X-axis-ti -line . . . . . . . . . . . . . print-Y-axis . . . . . . . . . . . . . . . . . . . . . .

R re-sear h-forward . . . . . . . . . . . . . . . . . 150

Read-only bu er . . . . . . . . . . . . . . . . . . . . . 65 Readying a graph . . . . . . . . . . . . . . . . . . . 203 Rebinding keys . . . . . . . . . . . . . . . . . . . . . 221 Re ursion . . . . . . . . . . . . . . . . . . . . . . . . . . 134 Re ursion and loops . . . . . . . . . . . . . . . . . 121 Re ursion without Deferments . . . . . . . 143 Re ursive De nition Parts . . . . . . . . . . . 135 Re ursive pattern: a

umulate . . . . . . . 142 Re ursive pattern: every . . . . . . . . . . . . 141 Re ursive pattern: keep . . . . . . . . . . . . . 143 Re ursive Patterns . . . . . . . . . . . . . . . . . . 140 re ursive- ount-words . . . . . . . . . . . . . 178 re ursive-graph-body-print . . . . . . . 210 re ursive-lengths-list-many-files

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Re ursively ounting words . . . . . . . . . . 173 regexp-quote . . . . . . . . . . . . . . . . . . . . . . 157 Region, what it is . . . . . . . . . . . . . . . . . . . . 44 Regular expression sear hes . . . . . . . . . . 149 Regular expressions for word ounting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Remainder fun tion, % . . . . . . . . . . . . . . . 258 Repetition (loops) . . . . . . . . . . . . . . . . . . 121 Repetition for word ounting . . . . . . . . 167 Retrieving text . . . . . . . . . . . . . . . . . . . . . 117 reverse . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 Ring, making a list like a . . . . . . . . . . . . 243 Robots, building . . . . . . . . . . . . . . . . . . . . 134 rotate-yank-pointer . . . . . . . . . . 117, 243 Run a program . . . . . . . . . . . . . . . . . . . . . . . 4

Index

S

Sample let expression . . . . . . . . . . . . . . . 38 save-ex ursion . . . . . . . . . . . . . . . . . . . . . 44 save-restri tion . . . . . . . . . . . . . . . . . . . 77 sear h-forward . . . . . . . . . . . . . . . . . . . . . 92 Sear hes, illustrating . . . . . . . . . . . . . . . . 149 senten e-end . . . . . . . . . . . . . . . . . . . . . . 149 Senten es, movement by . . . . . . . . . . . . . 149 set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 set-buffer . . . . . . . . . . . . . . . . . . . . . . . . . 26 set ar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 set dr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 set dr, example . . . . . . . . . . . . . . . . . . . 107 setq . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Setting a key globally . . . . . . . . . . . . . . . 220 Setting value of variable . . . . . . . . . . . . . . 17 `side effe t' de ned . . . . . . . . . . . . . . . . . 8 Simple extension in `.ema s' le . . . . . 224 simplified-beginning-of-buffer . . . . 52 `site-init.el' init le . . . . . . . . . . . . . . 213 `site-load.el' init le . . . . . . . . . . . . . . 213 Size of bu er . . . . . . . . . . . . . . . . . . . . . . . . 27 Solution without deferment . . . . . . . . . . 145 sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 Sour e level debugger . . . . . . . . . . . . . . . 235 Spe ial form . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Spe ial form of defun . . . . . . . . . . . . . . . . 29 Storing and utting text . . . . . . . . . . . . . . 89 `string' de ned . . . . . . . . . . . . . . . . . . . . . . 3 swit h-to-buffer . . . . . . . . . . . . . . . . . . . 26 Swit hing to a bu er . . . . . . . . . . . . . . . . . 26 Symbol names . . . . . . . . . . . . . . . . . . . . . . . . 6 Symbol without fun tion error . . . . . . . . 11 Symbol without value error . . . . . . . . . . . 11 Symboli expressions, introdu ed . . . . . . . 2 Symbols as a Chest of Drawers . . . . . . . 115 Syntax ategories and tables . . . . . . . . . 182

T

Tabs, preventing . . . . . . . . . . . . . . . . . . . . 219 `TAGS' le, reate own . . . . . . . . . . . . . . . 163 Tags in the Ema s sour es . . . . . . . . . . . 164 TAGS table, spe ifying . . . . . . . . . . . . . . . 51 Text between double quotation marks . . 3 Text Mode turned on . . . . . . . . . . . . . . . 218 Text retrieval . . . . . . . . . . . . . . . . . . . . . . . 117 the-the . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 `then-part' de ned . . . . . . . . . . . . . . . . . . 40

291 top-of-ranges . . . . . . . . . . . . . . . . . . . . . 198 triangle-bugged . . . . . . . . . . . . . . . . . . . 231 triangle-re ursively . . . . . . . . . . . . . . 137

Truth and falsehood in Ema s Lisp . . . . 43 Types of data . . . . . . . . . . . . . . . . . . . . . . . 13

U

Unbinding key . . . . . . . . . . . . . . . . . . . . . . 221 Uninitialized let variables . . . . . . . . . . . . 39

V

Variable initialization . . . . . . . . . . . . . . . 100 Variable number of arguments . . . . . . . . 14 Variable, example of, fill- olumn . . . . 10 Variable, setting value . . . . . . . . . . . . . . . . 17 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 `varlist' de ned . . . . . . . . . . . . . . . . . . . . 37 Version of Ema s, hoosing . . . . . . . . . . 225 Verti al axis printing . . . . . . . . . . . . . . . . 256

W

what-line . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

Whitespa e in lists . . . . . . . . . . . . . . . . . . . . 3 Whole graph printing . . . . . . . . . . . . . . . 267 Widening . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 Widening, example of . . . . . . . . . . . . . . . . 78 Word ounting in a defun . . . . . . . . . . . 181 Words and symbols in defun . . . . . . . . . 181 Words, ounted re ursively . . . . . . . . . . 173 Words, dupli ated . . . . . . . . . . . . . . . . . . 241 Writing a fun tion de nition . . . . . . . . . . 29 Wrong type of argument . . . . . . . . . . . . . . 14

X

X axis printing . . . . . . . . . . . . . . . . . . . . . 263

X-axis-element . . . . . . . . . . . . . . . . . . . . 265

Y

Y axis printing . . . . . . . . . . . . . . . . . . . . . 256 261 268 259 260

Y-axis- olumn . . . . . . . . . . . . . . . . . . . . . Y-axis- olumn Final version. . . . . . . . . Y-axis-label-spa ing . . . . . . . . . . . . . . Y-axis-ti . . . . . . . . . . . . . . . . . . . . . . . .

292 yank

Index ..........................

117, 249

yank-pop . . . . . . . . . . . . . . . . . . . . . . . . . . . 252

Z

zap-to- har . . . . . . . . . . . . . . . . . . . . . . . . 90 zerop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244

About the Author Robert J. Chassell has worked with GNU Ema s sin e 1985. He writes and edits, tea hes Ema s and Ema s Lisp, and speaks throughout the world on software freedom. Chassell was a founding Dire tor and Treasurer of the Free Software Foundation, In . He is o-author of the Texinfo manual, and has edited more than a dozen other books. He graduated from Cambridge University, in England. He has an abiding interest in so ial and e onomi history and ies his own airplane.

Related Documents

Emacs Lisp Intro
May 2020 6
Intro Emacs
November 2019 6
Lisp
November 2019 13
On Lisp
May 2020 9
Emacs Tutorial
November 2019 9
Tiddly Lisp
October 2019 17