Previous Next Contents

7. Functions

You saw one example of a function above. Here are some more:

> (+ 3 4 5 6)                   ;this function takes any number of arguments
18
> (+ (+ 3 4) (+ (+ 4 5) 6))     ;isn't prefix notation fun?
22
> (defun foo (x y) (+ x y 5))   ;defining a function
FOO
> (foo 5 0)                     ;calling a function
10
> (defun fact (x)               ;a recursive function
    (if (> x 0) 
      (* x (fact (- x 1)))
      1
  ) )
FACT
> (fact 5)
120
> (defun a (x) (if (= x 0) t (b (- x))))        ;mutually recursive functions
A
> (defun b (x) (if (> x 0) (a (- x 1)) (a (+ x 1))))
B
> (a 5)
T
> (defun bar (x)                ;a function with multiple statements in
    (setq x (* x 3))            ;its body -- it will return the value
    (setq x (/ x 2))            ;returned by its final statement
    (+ x 4))
BAR
> (bar 6)
13

When we defined foo, we gave it two arguments, x and y. Now when we call foo, we are required to provide exactly two arguments: the first will become the value of x for the duration of the call to foo, and the second will become the value of y for the duration of the call. In LISP, most variables are lexically scoped; that is, if foo calls bar and bar tries to reference x, bar will not get foo's value for x.

The process of assigning a symbol a value for the duration of some lexical scope is called binding.

You can specify optional arguments for your functions. Any argument after the symbol &optional is optional:

> (defun bar (x &optional y) (if y x 0))
BAR
> (defun baaz (&optional (x 3) (z 10)) (+ x z))
BAAZ
> (bar 5)
0
> (bar 5 t)
5
> (baaz 5)
15
> (baaz 5 6)
11
> (baaz)
13

It is legal to call the function bar with either one or two arguments. If it is called with one argument, x will be bound to the value of that argument and y will be bound to nil; if it is called with two arguments, x and y will be bound to the values of the first and second argument, respectively.

The function baaz has two optional arguments. It specifies a default value for each of them: if the caller specifies only one argument, z will be bound to 10 instead of to nil, and if the caller specifies no arguments, x will be bound to 3 and z to 10.

You can make your function accept any number of arguments by ending its argument list with an &rest parameter. LISP will collect all arguments not otherwise accounted for into a list and bind the &rest parameter to that list. So:

> (defun foo (x &rest y) y)
FOO
> (foo 3)
NIL
> (foo 4 5 6)
(5 6)

Finally, you can give your function another kind of optional argument called a keyword argument. The caller can give these arguments in any order, because they're labelled with keywords.

> (defun foo (&key x y) (cons x y))
FOO
> (foo :x 5 :y 3)
(5 . 3)
> (foo :y 3 :x 5)
(5 . 3)
> (foo :y 3)
(NIL . 3)
> (foo)
(NIL)

An &key parameter can have a default value too:

> (defun foo (&key (x 5)) x)
FOO
> (foo :x 7)
7
> (foo)
5


Previous Next Contents