Lisp tutorial 3: Functions and forms

We've already seen that expressions can be nested -- we used the example

(- (* z 2) 1)
-- with the implication that the inner expressions are evaluated automatically, to prepare the parameters for the outer one.

We've also seen that you can suppress the evaluation of something, by writing a quote mark before it: for example,

(- '(* z 2) 1)
would not make sense, because the inner expression is not evaluated to a number, but remains as a list (because of the quote mark), and you can't subtract a number from a list.

It's possible to ask for a list (such as a quoted list) to be treated as a piece of program, and evaluated. The function for doing this is called eval (short for evaluate, of course). So, we could write

(- (eval '(* z 2)) 1)
and that would have the same result as
(- (* z 2) 1)
because the eval effectively uses up the quote.

However, all normal functions have their parameters evaluated automatically for them.

This is where we come to the difference between functions and special forms, mentioned in the previous section. Special forms look like functions, but their sub-expressions are not all automatically evaluated for them.

For example, choosing between two possibilities is done by a special form, called if. if takes three sub-expressions: the first is the condition, the second is the choice to take if the condition is true, and the third is the choice to take if the condition is false. So, to choose the largest of a and b, we could write

(if (> a b)

That particular example would work alright even if if were an ordinary function, because it wouldn't matter that both the "then" case and the "else" case were evaluated, but when either or both of those cases has side-effects, you'd then get the side-effects of both. For example, if you didn't want the result of which of a and b is larger, but wanted to print a message, you could write

(if (> a b)
  (print "a is larger")
  (print "b is larger"))
If if were an ordinary function, and not a special form, both the messages would get printed.

On the whole, Lisp does not guarantee which order sub-expressions are evaluated in -- in principle, on a multi-CPU computer, they could all be evaluated at the same time. This is why progn is a special form: it guarantees that its sub-expressions are evaluated in the order given.

One of the special forms is most fundamental, and in fact you could do with just that one, and fake all the others, and that is one called quote. In fact,

is just an abbreviation for
(quote a)
(Such abbreviations are called syntactic sugar; they're not really necessary, but make things a bit sweeter to read and shorter to type.) If you evaluate (quote a), you get a.

When the Lisp system displays answers back to you, it will use the special form quote, rather than the quote character.

If if were a function (let's call it fif, for function-if), you could use quote to get the right effect, by writing

(fif (> a b)
  '(print "a is larger")
  '(print "b is larger"))
and having fif call eval either its second sub-expression or its third one, as both of them would have been passed in as lists, rather than having been run as print functions.

[lisp] [computing]
John C. G. Sturdy
[John's home] Last modified: Thu Nov 1 14:56:57 GMT 2007