The two strings the user types are used as values of the function arguments fromand to(in that order), and the command runs to completion. Thus, interactivesupplies values to the function's arguments in the order of the sections of the prompt string.
The use of interactivedoes not preclude calling the function from other Lisp code; in this case, the calling function needs to supply values for all arguments. For example, if we were interested in calling our version of replace-stringfrom another Lisp function that needs to replace all occurrences of "Bill" with "Deb" in a file, we would use
(replace-string "Bill" "Deb")
The function is not being called interactively in this case, so the interactivestatement has no effect; the argument fromis set to "Bill," and tois set to "Deb."
Getting back to our count-words-buffercommand: it has no arguments, so its interactivecommand does not need a prompt string. The final modification we want to make to our command is to add a documentation string (or doc string for short), which is shown by online help facilities such as describe-function( C-h f). Doc strings are normal Lisp strings; they are optional and can be arbitrarily many lines long, although, by convention, the first line is a terse, complete sentence summarizing the command's functionality. Remember that any double quotes inside a string need to be preceded by backslashes.
With all of the fixes taken into account, the complete function looks like this:
(defun count-words-buffer ( )
"Count the number of words in the current buffer;
print a message in the minibuffer with the result."
(interactive)
(save-excursion
(let ((count 0))
(goto-char (point-min))
(while (< (point) (point-max))
(forward-word 1)
(setq count (1+ count)))
(message "buffer contains %d words." count))))
11.2 Lisp Primitive Functions
Now that you've seen how to write a working command, we'll discuss Lisp's primitive functions. These are the building blocks from which you'll build your functions. As mentioned above, Lisp uses functions where other languages would use operators, that is, for arithmetic, comparison, and logic. Table 11-3shows some Lisp primitive functions that are equivalent to these operators.
Table 11-3. Lisp primitive functions
Arithmetic |
+ , - , * , / |
% (remainder) |
1+ (increment) |
1- (decrement) |
max , min |
Comparison |
> , < , >= , <= |
/= (not equal) |
= (for numbers and characters) |
equal (for strings and other complex objects) |
Logic |
and , or , not |
All the arithmetic functions except 1+
, 1-
, and %
can take arbitrarily many arguments, as can and
and or
. An arithmetic function returns floating point values only if at least one argument is a floating point number, so for example, (/ 7.0 4)
returns 1.75, and (/ 7 4)
returns 1. Notice that integer division truncates the remainder.
It may seem inefficient or syntactically ugly to use functions for everything. However, one of the main merits of Lisp is that the core of the language is small and easy to interpret efficiently. In addition, the syntax is not as much of a problem if you have support tools such as Emacs's Lisp modes to help you.
We have seen that a statement block can be defined using the letfunction. We also saw that whileand save-excursioninclude statement blocks. Other important constructs also define statement blocks: prognand other forms of let.
progn, the most basic, has the form:
(progn
statement-block )
prognis a simple way of making a block of statements look like a single one, somewhat like the curly braces of Java or the begin
and end
of Pascal. The value returned by prognis the value returned by the last statement in the block. prognis especially useful with control structures like if(see the following discussion) that, unlike while, do not include statement blocks.
The letfunction has other forms as well. The simplest is:
(let ( var1 var2 ...)
statement-block )
In this case, instead of a list of ( var value )
pairs, there is simply a list of variable names. As with the other form of let, these become local variables accessible in the statement block. However, instead of initializing them to given values, they are all just initialized to nil
. You can actually mix both forms within the same letstatement, for example:
(let ( var1 (var2 value2) var3 ...)
statement-block )
In the form of letwe saw first, the initial values for the local variables can be function calls (remember that all functions return values). All such functions are evaluated before any values are assigned to variables. However, there may be cases in which you want the values of some local variables to be available for computing the values of others. This is where let*, the final version of let, comes in. let*steps through its assignments in order, assigning each local variable a value before moving on to the next.
For example, let's say we want to write a function goto-percentthat allows you to go to a place in the current buffer expressed as a percentage of the text in the buffer. Here is one way to write this function:
(defun goto-percent (pct)
(interactive "nGoto percent: ")
(let* ((size (point-max))
(charpos (/ (* size pct) 100)))
(goto-char charpos)))
As we saw earlier, the interactivefunction is used to prompt users for values of arguments. In this case, it prompts for the integer value of the argument pct. Then the let*function initializes sizeto the size of the buffer in characters, then uses that value to compute the character position charposthat is pct(percent) of the buffer's size. Finally, the call of goto-charcauses point to be moved to that character position in the current window.
The important thing to notice is that if we had used letinstead of let*, the value of sizewould not be available when computing the value of charpos. let*can also be used in the ( var1 var2 ... )
format, just like let, but there wouldn't be any point in doing so.
Читать дальше