Previous Table of Contents Next


2.8. Functions

We have been discussing functions as commands for the computer to do something.

More specifically, to quote the section “What Is a Function?” of The GNU Emacs Lisp Reference Manual:

A function is a rule for carrying on a computation given several values called arguments. The result of the computation is called the value of the function. The computation can also have side effects: lasting changes in the values of variables or the contents of data structures.

Emacs Lisp has three kinds of functions: the sort that you and others write in Lisp using defun, the anonymous sort we mentioned previously that begin with lambda, and primitive functions that are written in the C programming language. These latter functions are called built-in functions or subrs (for subroutine) and are written to provide a low-level interface to operating system services or to run fast.

Technically speaking, a special form, such as defun, is not a function because it does not evaluate all its arguments in the usual way.

Likewise, a macro is not a function. A macro is a construct defined in Lisp that translates an expression you write into an equivalent expression that the Lisp interpreter evaluates instead. This way, you can do for yourself the sorts of things that special forms can do.

A function that contains an interactive declaration, as shown previously, is called a command because a user can invoke it interactively. Such a function can also be called indirectly as part of another function; in this context, the interactive declaration is ignored by the Lisp interpreter.

Finally, we should note that a keystroke command is a command bound to a key sequence. When you type in Emacs, you are calling functions.

2.9. The read-eval-print Loop and Side Effects

To get a better understanding of how Lisp works, let us consider the read-eval-print loop and side effects. Although you can write simple customizations or extensions without understanding this, the concepts clarify some aspects of Lisp that otherwise would be mysterious.

The Lisp interpreter runs as code those expressions that you give it. We say that it “evaluates” those expressions, but that way of describing the process is merely a handy shorthand. In actuality, the Lisp interpreter first reads and then evaluates the expression. The two activities are separate. Although often linked—often enough linked so we can use evaluation as a fair shorthand—they are not the same.

When the Lisp interpreter reads an expression, it first converts the printed representation into the representation used internally. Second, it evaluates the internal representation. This means that it computes the value that the expression returns, and undertakes any other actions, called side effects, that the expression may cause. Third, the interpreter sometimes converts the result of the second step into a form that a person can read, and prints that.

The phrase side effects may sound peculiar: so-called side effects are often actions that we humans think are important, such as moving the cursor or copying a file. The phrase comes from the notion of a computer as a person or, more recently, a machine for undertaking calculations. It is a sad accident of history that the word computer, originally the term for a person who did arithmetic calculations, should come to be the term applied to a type of machine that does all sorts of symbolic transformations, not merely arithmetic.

Initially side effects were other things that a computational machine could do, but were not considered its primary purpose. Moreover, Lisp was based on the premise that what you see as the result of evaluation, the value returned, is what you want. (Or, if you personally do not want to see a value that is an intermediate part of a calculation, the computer does, because it needs that value to complete its calculation.)

For example, when you evaluate the overall expression (+ 2 (+ 1 1)), the first list to be evaluated is (+ 1 1). You, the human reader, do not want to see the result of that; you want to see the result of the whole expression. But for the computer to calculate the whole expression, it has to calculate the (+ 1 1) expression first. Then, instead of passing that value to you, it uses it itself.

However, and this is very important, you could have looked at the result of that first expression. Indeed, when you are writing a program, you do look at the parts, and you do look at the values returned, or figure out in general what they will be. This is how you build programs, small part by small part into bigger wholes.


Previous Table of Contents Next