The original document was written by
Modified by:
All examples tested with
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
> (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
> (if t 5 6) 5 > (if nil 5 6) 6 > (if 4 5 6) 5
The last example is odd but correct.
Symbols like T and
NIL are called
'
> :this-is-a-keyword :THIS-IS-A-KEYWORD > :so-is-this :SO-IS-THIS > :me-too :ME-TOO
An integer number [FIXNUM] is a sequence of digits optionally preceded by
a plus
5 17 -34 +6 3.1415 1.722e-15
The standard arithmetic functions are all available:
|
+ |
||
|
- |
||
|
* |
||
|
/ |
||
|
truncate |
||
|
rem |
||
|
sin |
||
|
cos |
||
|
tan |
||
|
sqrt |
||
|
exp |
||
|
expt |
> (/ 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.
A cons is just a
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
You can build many structures out of conses. Perhaps the simplest is a
linked list.
> (list 4 5 6) (4 5 6)
Notice that Lisp prints linked lists a special way.
> (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.
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 = ()
List Accessors
There are several different approaches to name the accessor
functions for elements of conses and lists.
equivalent to | |
(1 2 3 4 5 6 7 8) | ||||
|
(nth 0 ... ) | → |
1 | |||
|
(nth 1 ... ) | → |
2 | |||
|
(nth 2 ... ) | → |
3 | |||
|
(nth 3 ... ) | → |
4 | |||
|
(nth 4 ... ) | → |
5 | |||
|
... | |||||
(nthcdr 0 ... ) | → |
(1 2 3 4 5 6 7 8) | ||||
|
(nthcdr 1 ... ) | → |
(2 3 4 5 6 7 8) | |||
|
(nthcdr 2 ... ) | → |
(3 4 5 6 7 8) | |||
|
(nthcdr 3 ... ) | → |
(4 5 6 7 8) | |||
|
(nthcdr 4 ... ) | → |
(5 6 7 8) | |||
(nthcdr 5 ... ) | → |
(6 7 8) | ||||
|
... | |||||
→ |
(8) |
The traditional
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'
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 .
The function 'baaz' has two optional arguments.
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
> (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.
> (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.
> (defun foo (&key (x 5)) x) FOO > (foo :x 7) 7 > (foo) 5
Some functions can cause output. The simplest one is
print, which
prints its argument and then
> (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 second argument is a formatting template, which is a string
optionally containing formatting directives.
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:
|
|
[standard] - accepts any Lisp object and replaces it by the same printed representation which is produced by the print function. | ||
|
|
[aestethic] - tries to ' |
||
|
|
[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
The things which you type to the Lisp interpreter are called 'forms'.
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, if Lisp sees the form:
(+ 3 4)
then it treats + as
the name of a function.
Nyquist:
The
> 3 3 > 4 4 > 5 5 > *** 3 > *** 4 > *** 5 > ** 4 > * 4
See * , ** , *** , + , ++ , +++ , − .
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
One useful special form is the quote
form.
> (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.
> (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.
Binding is lexically scoped assignment.
(let ((variable-1 value-1) (variable-2 value-2) ... ) body)
The let function binds
'
> (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.
(let ((a nil) (b nil)) ... )
you can write:
(let (a b) ... )
The '
> (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.
> (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)) ... ))
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.
In Lisp, dynamically scoped variables are called 'special' variables.
Nyquist has no 'dynamic' scoping in the
In Nyquist every variable assigned with
setq or
setf at the
> (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
'
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
The function
> (make-array 4) ; 1-D array with 4 elements #(NIL NIL NIL NIL)
Array indices always
A string is a sequence of characters between double quotes. Nyquist
represents a string internally as a
|
"abcd" |
||
|
"\"" |
||
|
"\\" |
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
Certain forms in Lisp naturally define a memory location. For example, if
the value of 'x' is a list, then
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.
> (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.
Lisp uses the
Lisp provides a standard set of logical functions, for example
and,
or, and
not.
Lisp also provides several special forms for conditional execution. The
simplest of these
> (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
> (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.
(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
> (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
> (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', '
The simplest iteration construct in Lisp is
loop.
> (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.
> (dolist (x '(a b c)) (print x)) A B C NIL
dolist always
The most flexible, but also most complicated iteration form is
> (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 do* form is to
do as
let* is
The return special form is an
example of a nonlocal return. Another example is
> (defun foo (x) (return-from foo 3) x) FOO > (foo 17) 3
Actually, the
> (block foo (return-from foo 7) 3) 7
The return special form can return
from any block
> (block nil (return 7) 3) 7
Another form which causes a nonlocal exit is the
> (error "This is an error") error: This is an error
The error form applies format to its arguments, then places you in the debugger.
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 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.
mapcar, along with nameless lambda functions, can replace many loops.
Nyquist/XLISP:
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.
> (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)
Lisp provides a primitive for
> (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.
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
(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)
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.
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