Nyquist / XLISP 2.0 - Contents | Tutorials | Examples | Reference

# Lisp Hints

The original document was written by Geoffrey J. Gordon [ggordon@cs.cmu.edu], Friday, February 5, 1993, for CMUCL.

Modified by:

- Bruno Haible for CLISP.
- Tom Almy in 1995 for XLISP Plus.
- Edgar M. Franke [edgar-rft@web.de] in 2010 for Nyquist.

All examples tested with Nyquist 3.03 in November 2010.

## Table of Contents

1. Symbols
2. Numbers
3. Conses
4. Lists
5. Functions
6. Printing
7. Forms and the Top-Level Loop
8. Special Forms
9. Binding
10. Dynamic Scoping
11. Arrays
12. Strings
13. Setf
14. Booleans and Conditionals
15. Iteration
16. Non-local Exits
17. Funcall, Apply, and Mapcar
18. Lambda
19. Sorting
20. Equality
21. Some Useful List Functions

## 1 Symbols

A symbol is just a sequence of characters. There are restrictions on what you can include in a symbol and what the first character can be, but as long as you stick to letters, digits, and hyphens, you'll be safe. [Except that if you use only digits and possibly an initial hyphen, Lisp will think you typed an integer rather than a symbol.] Some examples of symbols:

    a
    b
    c1
    foo
    bar
    baaz-quux-garply

Some things you can do with symbols follow. Things after a '>' prompt are what you type to the Lisp interpreter, while other things are what the Lisp interpreter prints back to you. The semicolon ';' is Lisp's comment character. Everything from a ';' to the end of line is ignored.

    > (setq a 5)        ; store a number as the value of a symbol
    5

    > a                 ; take the value of a symbol
    5

    > (let ((a 6))      ; bind the value of a symbol temporarily to 6
        a)
    6

    > a                 ; the value returns to 5 once the let is finished
    5

    > (+ a 6)           ; use the value of a symbol as an argument to a function
    11

    > b                 ; try to take the value of a symbol which has no value
    error: unbound variable - b

There are two special symbols, T and NIL. The value of T is defined always to be T , and the value of NIL is defined always to be NIL. Lisp uses T and NIL to represent true and false. An example of this use is in the if statement, described more fully later:

    > (if t 5 6)
    5

    > (if nil 5 6)
    6

    > (if 4 5 6)
    5

The last example is odd but correct. NIL means false, and anything else means true. Unless we have a reason to do otherwise, we use T to mean true, just for the sake of clarity.

Symbols like T and NIL are called 'self-evaluating' symbols, because they evaluate to themselves. There is a whole class of self-evaluating symbols called 'keywords'. Any symbol whose name starts with a colon is a keyword. [See below for some uses for keywords.] Some examples:

    > :this-is-a-keyword
    :THIS-IS-A-KEYWORD

    > :so-is-this
    :SO-IS-THIS

    > :me-too
    :ME-TOO

Back to top

## 2 Numbers

An integer number [FIXNUM] is a sequence of digits optionally preceded by a plus sign '+' or a minus sign '-'. A floating point number [FLONUM] looks like an integer, except that it has a decimal point and optionally can be written in scientific notation. Here are some numbers:

    5
    17
    -34
    +6
    3.1415
    1.722e-15

The standard arithmetic functions are all available:

`` | `+` | - | addition
`` | `-` | - | subtraction
`` | `*` | - | multiplication
`` | `/` | - | division
`` | `truncate` | - | truncate a float to an integer
`` | `rem` | - | remainder of a division
`` | `sin` | - | sine
`` | `cos` | - | cosine
`` | `tan` | - | tangent
`` | `sqrt` | - | square root
`` | `exp` | - | natural exponent
`` | `expt` | - | math exponent

+ [addition], - [subtraction], * [multiplication], and / [division] accept any number of arguments and return a number according to type contagion. This means that as long as only integer numbers are given as arguments the result will always be an integer number, but as soon as at least one of the arguments is a floating number then the result will be a floating point number. Here are some examples:

    > (/ 3 2)               ; integer division causes rounding error
    1

    > (/ 3 2.0)             ; the 2.0 forces floating point computation
    1.5

    > (exp 1)               ; e
    2.71828

    > (exp 3)               ; e * e * e
    20.0855

    > (expt 3 4.2)          ; exponent with a base other than e
    100.904

    > (+ 5 6 7 (* 8 9 10))  ; the functions + - * / accept multiple arguments
    738

In Nyquist the valid range of integer numbers is limited by the size of a C 'long' value on the machine on which Nyquist is running.

Back to top

## 3 Conses

A cons is just a two-field record. The fields are called car and cdr, for historical reasons. On the first machine where Lisp was implemented, there were two assembly language instructions CAR and CDR which stood for 'contents of address register' and 'contents of decrement register'. Conses were implemented using these two registers.

Conses are created by the cons function:

    > (cons 4 5)            ; Allocate a cons. Set the car to 4 and the cdr to 5
    (4 . 5)

    > (cons (cons 4 5) 6)
    ((4 . 5) . 6)

    > (car (cons 4 5))
    4

    > (cdr (cons 4 5))
    5

Back to top

## 4 Lists

You can build many structures out of conses. Perhaps the simplest is a linked list. The car [the first element] of each cons points to one of the elements of the list, and the cdr [the rest of the elements] points either to another cons or to NIL. You can create such a linked list with the list function:

    > (list 4 5 6)
    (4 5 6)

Notice that Lisp prints linked lists a special way. It omits some of the periods and parentheses. The rule is that if the cdr of a cons is NIL, Lisp doesn't bother to print the period or the NIL, and if the cdr of cons A is cons B, then Lisp doesn't bother to print the period for cons A or the parentheses for cons B. So:

    > (cons 4 nil)
    (4)             ; (4 . nil)

    > (cons 4 (cons 5 6))
    (4 5 . 6)       ; (4 . (5 . 6))

    > (cons 4 (cons 5 (cons 6 nil)))
    (4 5 6)         ; (4 . (5 . (6 . nil)))

The last example is exactly equivalent to the call:

    (list 4 5 6)

Note that NIL now means the list with no elements. The cdr of (a b), a list with 2 elements, is (b), a list with 1 element, and the cdr of (b), a list with 1 element, is NIL, which therefore must be a list with no elements.

The car and cdr of NIL are defined to be NIL.

If you store your list in a variable, you can make it act like a stack:

    > (setq a nil)
    NIL             ; A = ()

    > (push 4 a)
    (4)             ; A = (4)

    > (push 5 a)
    (5 4)           ; A = (5 4)

    > (pop a)
    5               ; A = (4)

    > (pop a)
    4               ; A = ()

    > (pop a)
    NIL             ; A = ()

See pop, push, setq.

List Accessors

There are several different approaches to name the accessor functions for elements of conses and lists. The 'traditional' Lisp still uses function names like car and cdr while the 'modern' Lisp uses more descriptive names like first and rest. This leads to the situation that in most Lisps today the list accessor functions are available under different names for the same functions:

modern | — | traditional |  | equivalent to | `` | (1 2 3 4 5 6 7 8)
first | — | car | `` | (nth 0 ... ) | `` → | 1
second | — | cadr | `` | (nth 1 ... ) | `` → | 2
third | — | caddr | `` | (nth 2 ... ) | `` → | 3
fourth | — | cadddr | `` | (nth 3 ... ) | `` → | 4
| `` | (nth 4 ... ) | `` → | 5
| `` | ...
| (nthcdr 0 ... ) | `` → | (1 2 3 4 5 6 7 8)
rest | — | cdr | `` | (nthcdr 1 ... ) | `` → | (2 3 4 5 6 7 8)
| cddr | `` | (nthcdr 2 ... ) | `` → | (3 4 5 6 7 8)
| cdddr | `` | (nthcdr 3 ... ) | `` → | (4 5 6 7 8)
| cddddr | `` | (nthcdr 4 ... ) | `` → | (5 6 7 8)
| (nthcdr 5 ... ) | `` → | (6 7 8)
| `` | ...
last |  | `` → | (8)

The traditional c..r-functions are available in even more variations, see car, cdr, cadr, cddr, caaar...caddr, cdaar...cdddr, caaaar...cadddr, and cdaaar...cddddr.

Back to top

## 5 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)            ; defining a function
        (+ x y 5))
    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
        (setq x (* x 3))          ; in its body. It will return the value
        (setq x (/ x 2))          ; returned by its final statement
        (+ x 4))
    BAR

    > (bar 6)
    13

See + , − , * , / , = , > , defun, if , setq. 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', then '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

See + , defun, if . 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)

See defun. Finally, you can give your function another kind of optional argument called a &key '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)

See defun. An &key parameter can have a default value too:

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

    > (foo :x 7)
    7

    > (foo)
    5

Back to top

## 6 Printing

Some functions can cause output. The simplest one is print, which prints its argument and then returns it:

    > (print 3)
    3            ; screen output
    3            ; return value

The first 3 above was printed, the second was returned.

If you want more complicated output, you will need to use format. Here's an example:

    > (format t "An atom: ~S~%and a list: ~S~%and an integer: ~A~%"
              nil (list 5) 6)
    An atom: NIL          ; screen output
    and a list: (5)       ; screen output
    and an integer: 6     ; screen output
    NIL                   ; return value

See list. The first argument to format is either T , NIL, or a stream. T specifies output to the terminal. NIL means not to print anything but to return a string containing the output instead. Streams are general places for output to go. They can specify a file, or the terminal, or a printer device. This tutorial will not describe streams in any further detail.

The second argument is a formatting template, which is a string optionally containing formatting directives. All remaining arguments may be referred to by the formatting directives. Lisp will replace the directives with some appropriate characters based on the arguments to which they refer and then print the resulting string.

The format function always returns NIL unless its first argument is NIL, in which case it prints nothing and returns a string.

There are several different directives available:

`` |
`~S`
| - | [standard] - accepts any Lisp object and replaces it by the same printed representation which is produced by the print function.
`` |
`~A`
| - | [aestethic] - tries to 'pretty-print' its argument.
`` |
`~%`
| - | [linebreak] - is always replaced by a linebreak character or character sequence of the underlying operation system.
`` |
`~~`
| - | [tilde] - is replaced by a single '~' character.

If the last character in a line in a format template is a tilde, then the linebreak is ignored and the template continues with the next non-whitespace character in the next line.

Back to top

## 7 Forms and the Top-Level Loop

The things which you type to the Lisp interpreter are called 'forms'. The Lisp interpreter repeatedly reads a form, evaluates it, and prints the result. This procedure is therefore called the 'read-eval-print' loop, or REPL for short.

Some forms will cause errors. After an error, Lisp will put you into the debugger so you can try to figure out what caused the error.

In general, a form is either an atom, [for example a symbol, an integer, or a string] or a list. If the form is an atom, Lisp evaluates it immediately. Symbols evaluate to their value, integers and strings evaluate to themselves. If the form is a list, Lisp treats its first element as the name of a function. It evaluates the remaining elements recursively, and then calls the function with the values of the remaining elements as arguments.

For example, if Lisp sees the form:

    (+ 3 4)

then it treats + as the name of a function. It then evaluates 3 to get 3 and 4 to get 4, finally it calls + with 3 and 4 as the arguments. The + function returns 7, which Lisp prints.

Nyquist: A description of the debugger can be found in the Break Command Loop section and a detailed description of the evaluation process can be found in the Evaluator section of the XLISP manual.

The top-level loop provides some other conveniences. One particularly convenient convenience is the ability to talk about the results of previously typed forms. Lisp always saves its most recent three results, it stores them as the values of the symbols * , ** , and *** . For example:

    > 3
    3

    > 4
    4

    > 5
    5

    > ***
    3

    > ***
    4

    > ***
    5

    > **
    4

    > *
    4

See * , ** , *** , + , ++ , +++ , − .

Back to top

## 8 Special Forms

There are a number of special forms which look like function calls but aren't. These include control constructs such as if statements and do loops, assignments like setq, setf, push, and pop, definitions such as defun, and binding constructs such as let. Not all of these special forms have been mentioned yet, see below for examples.

One useful special form is the quote form. The quote function prevents its argument from being evaluated. For example:

    > (setq a 3)
    3

    > a
    3

    > (quote a)
    A

    > 'a            ; 'a is an abbreviation for (quote a)
    A

Another similar special form is the function form, it causes its argument to be interpreted as a function rather than being evaluated. For example:

    > (setq + 3)
    3

    > +
    3

    > '+
    +

    > (function +)
    #<Subr-+: #88b44d5e>

    > #'+                   ; #'+ is an abbreviation for (function +)
    #<Subr-+: #88b44d5e>

The function special form is useful when you want to pass a function as an argument to another function. See below for some examples of functions which take functions as arguments.

Back to top

## 9 Binding

Binding is lexically scoped assignment. It happens to the variables in a function's parameter list whenever the function is called. The formal parameters are bound to the actual parameters for the duration of the function call. You can bind variables anywhere in a program with the let special form, which looks like this:

    (let ((variable-1 value-1)
          (variable-2 value-2)
           ... )
      body)

The let function binds 'variable-1' to 'value-1', 'variable-2' to 'value-2', and so forth. Then it executes the statements in its body. The body of a let follows exactly the same rules that a function body does. Some examples:

    > (let ((a 3)) (+ a 1))
    4

    > (let ((a 2)
            (b 3)
            (c 0))
        (setq c (+ a b))
        c)
    5

    > (setq c 4)
    4

    > (let ((c 5))
        c)
    5

    > c
    4

See + , let, setq. Instead of:

    (let ((a nil)
          (b nil))
      ... )

you can write:

    (let (a b)
      ... )

The 'value-1', 'value-2', etc. inside a let form cannot reference the variables 'variable-1', 'variable-2', etc. that the let form is binding. For example:

    > (let ((x 1)
            (y (+ x 1)))  ; x is still unbound here
        y)
    error: unbound variable - x

If the symbol 'x' already has a global value, stranger happenings will result:

    > (setq x 7)
    7

    > (let ((x 1)
            (y (+ x 1)))  ; references to the global x
        y)
    8

The let* special form is just like let except that it allows values to reference variables defined earlier in the let* form. For example:

    > (setq x 7)
    7

    > (let* ((x 1)
             (y (+ x 1)))  ; references to x in the line before
        y)
    2

The let* form:

    (let* ((x a)
           (y b))
      ... )

is equivalent to the following let construct:

    (let ((x a))
      (let ((y b))
        ... ))

Back to top

## 10 Dynamic Scoping

The let and let* forms provide lexical scoping, which is what you expect if you're used to programming in C or Pascal. Dynamic scoping is what you get in BASIC. If you assign a value to a dynamically scoped variable, every mention of that variable returns that value until you assign another value to the same variable.

In Lisp, dynamically scoped variables are called 'special' variables. In Common Lisp special variables are declared with the 'defvar' special form. In Nyquist there is no 'defvar' form.

Nyquist has no 'dynamic' scoping in the Common Lisp sense.

In Nyquist every variable assigned with setq or setf at the top-level, outside of a function or a let binding, is a lexical scoped variable. Here is an example what this means:

    > (setq *variable* 5)         ; define a global variable
    5

    > (defun check-variable ()    ; define a function in global scope,
        *variable*)               ; returning the value of the variable
    CHECK-VARIABLE

    > (check-variable)            ; the CHECK-VARIABLE function returns
    5                             ; the global value of the variable

    > (let ((*variable* 10))      ; create a local binding for the variable
        (print (check-variable))  ; call CHECK-VARIABLE and print the return value
        (print *variable*))       ; print the local value of the variable
    5   ; return value of CHECK-VARIABLE
    10  ; variable value inside of LET
    10

See defun, let, print, setq. Because the 'check-variable' function was defined in global scope and therefore is lexically outside of the let form, the 'check-variable' function returns the variable's global value of 5, even if called from inside the let form, where the variable has a value of 10.

Important: In Nyquist there is no way to change the scoping behaviour of variables, so you must be careful where you define your variables. With Nyquist it's generally a good idea to prefer local let bindings over global variables.

By convention, the name of a global Nyquist variable begins and ends with a star * to signal that the variable might behave differently than the programmer expects.

Back to top

## 11 Arrays

The function make-array makes a 1-dimensional array. The aref function accesses its elements. All elements of an array are initially set to NIL. For example:

    > (make-array 4)        ; 1-D array with 4 elements
    #(NIL NIL NIL NIL)

Array indices always start at 0. See below for how to set the elements of an array.

Back to top

## 12 Strings

A string is a sequence of characters between double quotes. Nyquist represents a string internally as a variable-length array of characters. You can write a string containing a double quote by preceding the quote with a backslash. A double backslash stands for a single backslash. For example:

`` | `"abcd"` | - | has 4 characters
`` | `"\""` | - | has 1 character, a quote
`` | `"\\"` | - | has 1 character, a backslash

Here are some functions for dealing with strings:

    > (strcat "abcd" "efg")
    "abcdefg"                ; STRCAT concatenates strings

    > (char "abc" 1)
    #\b                      ; Lisp writes characters preceded by #\

    > (subseq "abc" 0 2)
    "ab"                     ; SUBSEQ extracts substrings

See char, strcat, subseq.

Back to top

## 13 Setf

Certain forms in Lisp naturally define a memory location. For example, if the value of 'x' is a list, then (nth 4 x) defines the fifth element of the list. Or, if the value of 'y' is a one-dimensional array, (aref y 2) defines the third element of the array.

The setf special form uses its first argument to define a place in memory, evaluates its second argument, and stores the resulting value in the resulting memory location. For example:

    > (setq a (make-array 3))
    #(NIL NIL NIL)

    > (aref a 1)
    NIL

    > (setf (aref a 1) 3)         ; store 3 in the second element of a
    3

    > a
    #(NIL 3 NIL)

    > (aref a 1)                  ; read the second element of a
    3

    > (setq b (list 1 2 3 4 5))
    (1 2 3 4 5)

    > (nth 4 b)
    5

    > (setf (nth 4 b) "five")     ; store "five" in the fifth element of b
    "five"

    > b
    (1 2 3 4 "five")

    > (nth 4 b)
    "five"

The setf function is the only way to set the elements of a list or an array.

Back to top

## 14 Booleans and Conditionals

Lisp uses the self-evaluating symbol NIL to mean false. Anything other than self-evaluating means true. Unless we have a reason not to, we usually use the self-evaluating symbol T to stand for true.

Lisp provides a standard set of logical functions, for example and, or, and not. The and and or connectives are short-circuiting, and will not evaluate any arguments to the right of the first one which evaluates to NIL, while or will not evaluate any arguments to the right of the first one which evaluates to T .

Lisp also provides several special forms for conditional execution. The simplest of these is if . The first argument of if determines whether the second or third argument will be executed:

    > (if t 5 6)
    5

    > (if nil 5 6)
    6

    > (if 4 5 6)
    5

If you need to put more than one statement in the 'then' or 'else' clause of an if statement, you can use the progn special form. progn executes each statement in its body, then returns the value of the final one:

    > (setq a 7)
    7

    > (setq b 0)
    0

    > (setq c 5)
    5

    > (if (> a 5)
        (progn
          (setq a (+ b 7))
          (setq b (+ c 8)))
        (setq b 4))
    13

An if statement which lacks either a 'then' or an 'else' clause can be written using the when or unless special form:

    > (when t 3)
    3

    > (when nil 3)
    NIL

    > (unless t 3)
    NIL

    > (unless nil 3)
    3

when and unless, unlike if , allow any number of statements in their bodies:

    (when x
      a
      b
      c)

is equivalent to:

    (if x
        (progn
          a
          b
          c))

For example:

    > (when t
        (setq a 5)
        (+ a 6))
    11

More complicated conditionals can be defined using the cond special form. A cond form consists of the symbol cond followed by a number of cond clauses, each of which is a list. The first element of a cond clause is the condition, the remaining elements [if any] are the actions:

    (cond (condition-1 action-1)
          (condition-2 action-2)
            ...
          (t default-action))

The cond form finds the first clause whose condition evaluates to true [does not evaluate to NIL]. It then executes the corresponding action and returns the resulting value. None of the remaining conditions are evaluated, nor are any actions except the one corresponding to the selected condition. For example:

    > (setq a 3)
    3

    > (cond
        ((evenp a) a)        ; if a is even return a
        ((> a 7) (/ a 2))    ; else if a is bigger than 7 return a/2
        ((< a 5) (- a 1))    ; else if a is smaller than 5 return a-1
        (t 17))              ; else return 17
    2

If the action in the selected cond clause is missing, then cond returns what the condition evaluated to:

    > (cond ((+ 3 4)))
    7

The Lisp case form is like a C 'switch' statement:

    > (setq x 'b)
    B

    > (case x
        (a 5)
        ((d e) 7)
        ((b f) 3)
        (t 9))
    3

The T clause at the end means that if 'x' is not 'a', 'd or e', or 'b or f', then the case form will return 9.

Back to top

## 15 Iteration

The simplest iteration construct in Lisp is loop. A loop construct repeatedly executes its body until it hits a return special form. For example:

    > (setq a 4)
    4

    > (loop
        (setq a (+ a 1))
        (when (> a 7) (return a)))
    8

    > (loop
        (setq a (- a 1))
        (when (< a 3) (return)))
    NIL

The next simplest is dolist. It binds a variable to the elements of a list in order and stops when it hits the end of the list:

    > (dolist (x '(a b c))
        (print x))
    A
    B
    C
    NIL

dolist always returns NIL. Note that the value of 'x' in the above example was never NIL. The NIL below the C was the value that dolist returned, printed by the read-eval-print loop.

The most flexible, but also most complicated iteration form is called do. A do form looks like this:

    > (do ((x 1 (+ x 1))    ; variable x, initial value 1, update with (+ x 1)
           (y 1 (* y 2)))   ; variable y, initial value 1, update with (* y 2)
          ((> x 5) y)       ; terminate if (> x 5), return the value of y
        (print y)
        (print 'working))
    1
    WORKING
    2
    WORKING
    4
    WORKING
    8
    WORKING
    16
    WORKING
    32

The first part of a do form specifies what variables to bind, what their initial values are, and how to update them. The second part specifies a termination condition and a return value. The last part is the body. A do form binds its variables to their initial values like a let, then checks the termination condition. As long as the condition is false, it executes the body repeatedly. When the condition becomes true, it returns the value of the return-value form.

The do* form is to do as let* is to let.

Back to top

## 16 Non-local Exits

The return special form is an example of a nonlocal return. Another example is return-from, which returns a value from the surrounding function:

    > (defun foo (x)
        (return-from foo 3)
        x)
    FOO

    > (foo 17)
    3

Actually, the return-from form can return from any named block, it's just that functions are the only blocks which are named by default. You can create a named block with the block special form:

    > (block foo
        (return-from foo 7)
        3)
    7

The return special form can return from any block named NIL. Loops are by default named NIL, but you can make your own NIL-named blocks:

    > (block nil
        (return 7)
        3)
    7

Another form which causes a nonlocal exit is the error form:

    > (error "This is an error")
    error: This is an error

The error form applies format to its arguments, then places you in the debugger.

Back to top

## 17 Funcall, Apply, and Mapcar

Earlier I promised to give some functions which take functions as arguments. Here they are:

    > (funcall #'+ 3 4)
    7

    > (apply #'+ 3 4 '(3 4))
    14

    > (mapcar #'not '(t nil t nil t nil))
    (NIL T NIL T NIL T)

funcall calls its first argument on its remaining arguments.

apply is just like funcall, except that its final argument should be a list. The elements of that list are treated as if they were additional arguments to a funcall.

The first argument to mapcar must be a function of one argument, mapcar applies this function to each element of a list and collects the results in another list.

funcall and apply are chiefly useful when their first argument is a variable. For instance, a search engine could take a heuristic function as a parameter and use funcall or apply to call that function on a state description. The sorting functions described later use funcall to call their comparison functions.

mapcar, along with nameless lambda functions, can replace many loops.

Nyquist/XLISP: In XLISP, a 'special form' of type FSUBR is not a function. This means that apply, funcall and mapcar only work with functions of type SUBR [built-in function] or CLOSURE [function defined by defun, flet, labels, or lambda], but with special forms of type FSUBR a 'bad argument type' error is signalled.

Back to top

## 18 Lambda

If you just want to create a temporary function and don't want to bother giving it a name, lambda is what you need.

    > #'(lambda (x)
          (+ x 3))
    #<Closure: #88b71ece>

    > (funcall * 5)
    8

The combination of lambda and mapcar can replace many loops. For example, the following two forms are equivalent:

    > (do ((x '(1 2 3 4 5) (cdr x))
           (y nil))
          ((null x) (reverse y))
        (push (+ (car x) 2) y))
    (3 4 5 6 7)

    > (mapcar #'(lambda (x) (+ x 2)) '(1 2 3 4 5))
    (3 4 5 6 7)

Back to top

## 19 Sorting

Lisp provides a primitive for sorting, sort:

    > (sort '(2 1 5 4 6) #'<)
    (1 2 4 5 6)

    > (sort '(2 1 5 4 6) #'>)
    (6 5 4 2 1)

The first argument to sort is a list, the second is a comparison function. Be careful, because sort is allowed to destroy its argument, so if the original sequence is important to you, make a copy before sorting the list.

Bug: In Nyquist 3.03 [November 2010] the XLISP sort function has a bug, so it's better to store the return value of sort in the original variable like this:

    (setq a '(3 1 4 1 5 9 6 7))  => (3 1 4 1 5 9 6 7)
    (setq a (sort a '<))         => (1 1 3 4 5 6 7 9)
    a                            => (1 1 3 4 5 6 7 9)

Back to top

## 20 Equality

Lisp has many different ideas of equality. Numerical equality is denoted by =. Two symbols are eq if and only if they are identical. Two copies of the same list are not eq, but they are equal.

    > (eq 'a 'a)
    T

    > (eq 'a 'b)
    NIL

    > (= 3 4)
    T

    > (eq '(a b c) '(a b c))
    NIL

    > (equal '(a b c) '(a b c))
    T

    > (eql 'a 'a)
    T

    > (eql 3 3)
    T

The eql predicate is equivalent to eq for symbols and to = for numbers.

The equal predicate is equivalent to eql for symbols and numbers. It is true for two conses if and only if their cars are equal and their cdrs are equal.

Back to top

## 21 Some Useful List Functions

These functions all manipulate lists:

    > (append '(1 2 3) '(4 5 6))    ;concatenate lists
    (1 2 3 4 5 6)

    > (reverse '(1 2 3))            ;reverse the elements of a list
    (3 2 1)

    > (member 'a '(b d a c))        ;set membership -- returns the first tail
    (A C)                           ;whose car is the desired element

Back to top

Nyquist / XLISP 2.0 - Contents | Tutorials | Examples | Reference