next up previous
Next: Evaluating Expressions Up: Emacs Lisp, The Language Previous: Introduction

Expressions - building blocks of a lisp program

A Lisp program is made up of a sequence of expressions. ``Running'' the program is equivalent to ``evaluating'' the expressions sequentially. In this section we look at the syntax of a lisp expression, i.e. how to write expressions and do various useful things with them.


 
Table 1: Different types of Lisp expressions. The (, ', ` symbols are part of the syntax. Except for some rules like what constitutes a valid identifier, and certain other extremely abstruse syntactic tokens, the above table shows almost the entire syntax of Emacs Lisp.
expr ::=   identifer ............ (1)
    $\vert$ constant or literal ............ (2)
    $\vert$ ( expr* ) ............ (3)
    $\vert$ 'expr ............ (4)
    $\vert$ `expr ............ (5)
 

Table 1 lists the different types of expressions that are possible in Lisp.

Instead of explaining the notation in words, a few examples here would do the job. Table 2 shows a set of examples for each of the types of expressions we have generically described above. For now, you can just assume that Type 5 are identical to Type 4. Each of the sample expressions is a valid lisp expression, syntactically. i.e. each of them can appear by themselves in a line of a valid lisp program.

Before we proceed let me tell you that what you see above is pretty close to the entire syntax of lisp expressions. Considering that a lisp program is made up a sequence of expressions (and comments, if it is a good lisp program - a semicolon character starts a comment; the end of line terminates one), you have already learnt almost all there is to know to start writing full programs :-) Yes, it is not really complete, and there are a few things that are yet to be specified, like what constitutes a valid identifier name and such, the different ways in which numeric constants can be representation etc. Such minor issues aside, you really do have, in the above table, practically all the ways in which you can build lisp expressions from the fundamental lexical elements. Compare this to the horrendous nonsense that passes for the syntax of a ``modern'' high-level language like C++ or Java.


 
Table 2: Various expression types. The designations Type (1), Type (2)
Expression Type Sample Expressions Comment
Type (1) x Identifiers
  foo  
Type (2) 10 Literals
  5.8  
  "Hello World"  
  nil  
Type (3) () Building complex expressions out
  (foo) of other expressions
  (factorial 10)  
  (+ 10 2)  
  (setq foo 10)  
  (factorial (+ 10 2))  
  (if foo 1 0)  
Type (4) '(0 1 2) Quoted expressions
  'foo  
Type (5) `(list (+ 1 2) 3)  
etc. are not standard. I have labelled them such for convenience of discourse here.  

Type (1) expressions define identifiers, straightforward enough.

Type (2) expressions define literals. A literal is nothing but a constant. Constants are typically integers, floating points, strings and characters. nil is a special literal. You can think of it as the equivalent of the value ``false'' in Pascal or C++. The opposite truth value of nil is represented by the symbol t. We will have more to say about nil later.

Type (3) expressions: This rule just says ``zero or more expressions separated by white space and enclosed in brackets is an expression.'' This is the rule that can be used recursively to make increasingly complicated expressions, and is essentially the rule that gives the lisp-ish touch to a program's look and feel.

() is special and very different from the others listed above. For now, just think of it as another way of writing nil. We will have more to say about both when we talk about lists.

The expression (foo) is a function call to function foo. This is how function calls are written in lisp. In fact, if any lisp expression (of Type (3) excluding ()) is evaluated, then the first symbol inside the brackets has to be the name of a function. The lisp interpreter flags an error otherwise.

Thus, (factorial 10) is a call to a function named factorial and we pass the value 10 as an argument. By the same token, (+ 10 2) is a call to a function named + that takes two arguments. ``But...'', you say, ``+ is an operator, right? What do you mean by ``a function named +'' ''. This brings us to an interesting point about lisp. In lisp, there is no difference between ``operators'' and ``functions''. All of them are lisp functions defined somewhere. What one would call an operator in Java or C++ is defined as a function in lisp. + - * / *= /= % are all lisp functions. This particular feature of lisp is radically different from all other modern and popular procedural languages, and hence takes a little getting used to. If you are a C++ programmer, now is a good time to disabuse yourself of any notion that operator overloading was invented by Dr. Stroustrup just for you. The sections on Lisp handling of types will further rub in this truth.

Looking at these examples afresh in light of the information that operators and functions are one and the same, we can make a few key observations about a few other features of lisp. The first is that lisp function names (all identifier names, actually) can contain ``special'' characters. So, foo123, a++, this->sucks, my**lifez**great, foo_&_bar, /, == are all valid names for variables and functions. This is a refreshing change from the ``alpha numeric and underscore only'' limitation that somewhat restricts one's creative juices from flowing freely.

Secondly, we note that Lisp uses the prefix notation for arithmetic expressions. I.e. while writing an arithmetic expression the ``operator'' precedes the operands. This is in contrast to the infix notation followed in C and the monstrosities that followed. This prefix notation business is a little weird at the start, but it solves so many problems that it is very much worth the effort to get used to it. Think about it: it wholly gets rid of precedence and associativity issues! How is that for an elegant solution to a pesky problem that haunts generation after generation of programmers!

Thirdly, there is no real distinction between ``unary'', ``binary'', ``ternary'' operators and so on. This is good for the programmer, as there are fewer details to be worried about. If you are a C programmer, can you tell me, quickly, what is computed by the following expression - i -- j;

The expression (setq foo 10), has the same pattern of some other expressions listed, but is interesting for other reasons and hence I have listed it above. setq is a predefined function that assigns values to variables. In Lisp, you need not declare variables explicitly before you assign values to them, you can start by assigning values to any variable name, and that variable will be brought into existence if it is not already. It suffices that you know this much for the time being. More on variables, and assigning values to them, later.

We will deal with Type (4) and Type (5) expressions in the next section.


next up previous
Next: Evaluating Expressions Up: Emacs Lisp, The Language Previous: Introduction
Sriram Karra
2005-01-06