Lisp Resources: where to find the best information on Common Lisp and Common Lisp Music
Symbols and
Numbers: using characters, integers, real numbers, complex
numbers, t, and nil.
Conses:
using car and cdr
Local and Global
Variables: using defvar, let, setq, setf,
and let*
The Loop: the
ever so, ever so, ever so useful forms of loop
Structures: creating structures using
defstruct
Formatting: Lisp's general printing
routine (similar to C's printf and sprintf)
Functions: creating user-defined
functions with defun; assigning &key
and &optional parameters; using
if and cond statements; and
watching the recursive process with trace
>a >x >spin >repeat-melodic-frag
t and nil are special
self-evaluating characters predefined as true and false.
> 55 ;integer >-55 ;also an integer >3.1415 ;real number >2/3 ;rational >#c(1.722e-15 0.75) ;complex number #c(r i) where ;r is the real part and i the imaginary
+, -, *, /, mod, sin, cos, sqrt, exp, expt,
etc. are all available as arithmetic functions. When mixing number types,
the outcome follows type contagion: integer and rational yield a rational,
rational and real yield a real, real and complex yield a complex.
cons is a two-field record made up of
car (contents of address register) and
cdr (contents of decrement registers). In essence, the first
element of any cons is the car
and the second is the cdr.
>(cons 1 2) ;set the cons: car set to 1, cdr set to 2 (1 . 2) >(car (cons 1 2)) 1 >(cdr (cons 1 2)) 2 >(cons (cons 1 2) 3) ;nested cons statements - the car ;of this cons is (1 . 2) and the cdr is 3 ((1 . 2) . 3)
Conses are very useful for building structures and
accessing the data inside lists. When the cdr of a
cons is nil, Lisp won't print
anything in its place.
>(cons 1 nil) (1)
cdr of cons A
is cons B, Lisp won't print the period for
cons A or the parentheses for cons B.
>(cons 1 (cons 2 3) (1 2 . 3)
Conses can be used to build linked lists. Notice
how the two Lisp calls below are equivalent.
>(cons 1 (cons 2 (cons 3 nil))) (1 2 3) ;only the car of each cons is printed by Lisp. >(list 1 2 3) (1 2 3)
defvar is used to define a global
variables. This type of definition acts globally throughout the program.
>(defvar a 22) >a 22 >defvar b (+ a 14) ;a can now be referenced freely in the program 36
let is used to define a local variable. Be
careful with the use of parenthesis around the variables in a let
statement. let (x y) (...)) defines X and
Y as local variables while let ((x y)) (...)) defines
X as a local variable with a value of Y.
(let ((a 1) (b 2)) (+ a b 3)) 6
setf and setq are used to
change a variable's binding. Notice how the following two examples achieve
the same results.
>(let ((a 1) (b 2) (c 3)) (+a b c)) 6 >(let (a b c) (setq a 1) (setq b 2) (setq c 3) (+ a b c)) 6
setq is really good at changing variables, but if
one wanted to only change part of a variable, setf is
a better choice.
>(setq pent-scale '(c d e g a)) (C D E G A) >(setf (first pent-scale) 'b) B >pent-scale (B D E G A) >(setf (fourth pent-scale) 'f#) F# >pent-scale (B D E F# A)
let* is like let except that
variables can be defined earlier in the let
statement. The form (let* ((x a) (y b))
is equal to (let ((x a)) (let ((y b))). If
a symbol already has a global value and let is used to
change the new value won't hold. The value of let*
will hold throughout the let* statement. Compare the
results of the following examples.
>(setq a 5) 5 >(let ((a 1) (y (+ a 1))) ;y does not reference the let's binding y) ;of a to 1. 6 ;it still thinks a was 5 >(let* ((a 1) (y (+ a 1))) ;here, however, y does reference the let* y) ;binding of a to 1 2
loop
statement. Here is the basic form:
>(loop for i from 1 to 3 do (print i)) 1 2 3 NIL ;NIL is the value returned by loop
by - in this case, skipping by two:
>(loop for i from 1 to 5 by 2 do (print i)) 1 3 5 NIL
in accesses elements in a list.
>(loop for entry in '(A B C) do (print entry)) A B C NIL
repeat repeats.
>(loop repeat 2 do (print "hello world") "hello world" "hello world"
while:
>(setq x 10) ;set x to 10 (loop while (< = x 12) do ;while x is less or equal to 12 (setq x (+ x 1)) ;increment x by 1 (print x)) 11 12 13 NIL
until:
>(setq x 10) (loop until (> x 12) do (setq x (+ x 1) (print x)) 11 12 13 NIL
with declares variables local to the loop.
>(defvar x 7) (loop with (x) for i from 1 to 5 do (setq x (* i i)) 25 ;value of local x 7 ;value of global x
return breaks the loop at any point, returning a
value as the result of loop.
>(loop for i from 1 to 10 do (print i) (if (> i 2) (return "done")) ) 1 2 3 "done"
finally specifies what to do once the loop is
complete.
>(loop for i from 1 to 4 do (setq total (+ total i)) finally (return total))) 10
loop increments local variables before the
termination test.
>(loop for i from 1 to 3 do (print i finally (return (* i i ))) 1 2 3 16 ;not 9!
collecting creates a list and returns it as the
value of the loop.
>(loop for i from 1 to 5 collecting (* i i)) (1 4 9 16 25)
summing adds up a total and returns it as the
value of the loop.
>(loop for i from 1 to 5 summing (* i i)) 55
defstruct defines structures in Lisp. Structures
have a name, and a series of "slots". Functions are automatically
generated to access the data. Here is an example structure type called
"composition" which contains slots for information on the piece:
>(defstruct composition instrumentation duration form harmony rhythm) COMPOSITION
defstruct automatically creates a function called
make-composition which allows the creation of
instances. So to use the structure, we need to assign a variable to an
instance of composition.
>(setf composition1 (make-composition)) #S(COMPOSITION :INSTRUMENTATION NIL :DURATION NIL :FORM NIL :HARMONY NIL :RHYTHM NIL)
NIL. We can check the value of specific
cases by calling them individually:
>(composition-form composition1) NIL
setf can be used to assign values to slots.
>(setf (composition-form composition1) 'ABA) ABA >(composition-form composition1) ABA
>(setf composition1 (make-composition :instrumentation 'piano :duration '22min :form 'ABA :Harmony 'GMaj :rhythm '4.4)) #S(COMPOSITION :INSTRUMENTATION PNO :DURATION 22MIN :FORM ABA :HARMONY GMAJ :RHYTHM 4/4)
format is the general printing routine
in Lisp. There are two general forms of
format: (format t string args) and
(format NIL string args).
(format t string args) prints the string to the
screen but with arguments substituted into the string in places where
there were entries like ~X.
>(format t "hello world") hello world NIL >(format t "The value of pi is ~S" pi) The value of pi is 3.141592653589793d0
(format NIL string args) is similar to the t form
but instead of printing the result, it returns it as a string.
>(format NIL "(first '~S) is ~S" '(A B C) (first '(A B C))) "(first '(A B C)) is A"
~%: insert a carriage return (CR)
~&: insert a CR unless already at the
beginning of a line
~S: insert an arbitrary Lisp expression then print
it just as it would be returned
~A: (ASCII) similar to ~S but
if one argument is a string, its double quotes will be dropped
~D: insert an integer
~F: insert a floating point number
(defun name
parameter-list body). Here is an example:
>(defun square (x) (* x x)) SQUARE >(square 2) 4 >(square 1.4142158) 2.0000064
>(defun fourth-power (x) (square (square x))) FOURTH POWER >(fourth-power 2) 16
if statements take the form of: (if test
then else). Here is how they might be used in a function:
>(defun diff (x y) (if (> x y) (- x y) (- y x))) ;this function will always return a ;positive value or 0
if statements can become very complex when there
are too many conditions. For example one can easily imagine a situation
such as: (if A B (if C D (if E F G) which would be
read as "if A then B else, if C then D else, if E then F else
G. cond (conditional) statements are used in
situations like this. cond takes the form of:
(cond (testa form1a form2a...resulta) (cond (testb form1b form2b...resultb) (cond (testc form1c form2c...resultc) (cond (testn form1n form2n...resultn)
t as the last clause of the
cond statement because if none of the others work then
it will be the default. A call might look like this:
>(cond (A B) (C D) (t E))
cond; if these weren't here, cond
would evaluate > as a test and an unbound variable error would occur.
>(defun diff (x y) (cond ((> x y) (- x y)) (+ (-y x))))
>(defun power (x y) (if (= y 0) 1 (* x (power x (- y 1)))) ;the else clause of the if statement ;references power >(power 3 4) ;3 to the 4th power 81
diff needs two arguments or an error message will
result. It is often useful to define optional arguments for complex
functions. This is done using &optional. Any argument
following the &optional is optional. A default value
is given to each.
>(defun plus (&optional (a 0) (b 1) (c 2)) (+ a b c)) PLUS >(plus) 3 ;all default values used >(plus 5 6) 13 ;a = 5, b = 6, c default to 2 >(plus 5 6 7) 18 ;a = 5, b = 6, c = 7
&key(keyword) arguments,
can be given in any order because they are defined by keywords. They work
like this:
>(defun plus (&key a b c) (+ a b c)) PLUS >(plus :a 5 :b 6 :c 1) 12 >(plus :c 1 :a 5 :b 6) 12
trace allows us to watch the recursive process. If
we wanted to watch the recursive process of of the function
power we used earlier we simply ask
trace to go through the steps:
>(defun power (x y) (if (= y 0) 1 (* x (power x (- y 1)))) ;references power >(power 3 4) 81 >(trace power) POWER >(power 3 4) 0: (POWER 3 4) 1: (POWER 3 3) 2: (POWER 3 2) 3: (POWER 3 1) 4: (POWER 3 0) 4: (POWER 1) 3: (POWER 3) 2: (POWER 9) 1: (POWER 27) 0: (POWER 81) 81