Lisp Tutorial
Lisp Tutorial
Lisp Tutorial
Audience
This reference has been prepared for the beginners to help them understand the basic
to advanced concepts related to LISP Programming language.
Prerequisites
Before you start doing practice with various types of examples given in this reference,
we assume that you are already aware of the fundamentals of computer programming
and programming languages.
All the content and graphics published in this e-book are the property of Tutotorials
Point (I) Pvt. Ltd. The user of this e-book is prohibited to reuse, retain, copy, distribute
or republish any contents or a part of contents of this e-book in any manner without
written consent of the publisher.
You strive to update the contents of our website and tutorials as timely and as precisely
as possible, however, the contents may contain inaccuracies or errors. Tutorials Point
(I) Pvt. Ltd. provides no guarantee regarding the accuracy, timeliness or completeness
of our website or its contents including this tutorial. If you discover any errors on our
website or in this tutorial, please notify us at contact@tutorialspoint.com
LISP
Table of Contents
About the Tutorial ............................................................................................................................................. i
Audience ........................................................................................................................................................... i
Prerequisites ..................................................................................................................................................... i
Copyright & Disclaimer...................................................................................................................................... i
Table of Contents ............................................................................................................................................. ii
1.
OVERVIEW ........................................................................................................................................... 1
Features of Common LISP................................................................................................................................. 1
Applications Developed in LISP ........................................................................................................................ 1
2.
3.
4.
5.
6.
MACROS ............................................................................................................................................. 14
ii
LISP
Defining a Macro ............................................................................................................................................ 14
7.
VARIABLES ....................................................................................................................................... 15
Global Variables ............................................................................................................................................. 15
Local Variables ............................................................................................................................................... 16
8.
CONSTANTS ...................................................................................................................................... 18
9.
OPERATORS ..................................................................................................................................... 19
Arithmetic Operations.................................................................................................................................... 19
Comparison Operations ................................................................................................................................. 20
Logical Operations on Boolean Values............................................................................................................ 22
Bitwise Operations on Numbers..................................................................................................................... 24
iii
LISP
Keyword Parameters ...................................................................................................................................... 43
Returning Values from a Function .................................................................................................................. 43
Lambda Functions .......................................................................................................................................... 45
Mapping Functions......................................................................................................................................... 45
iv
LISP
21. VECTORS............................................................................................................................................ 89
Creating Vectors ............................................................................................................................................. 89
Fill Pointer Argument ..................................................................................................................................... 90
23. TREE.................................................................................................................................................... 98
Tree as List of Lists ......................................................................................................................................... 98
Tree Functions in LISP..................................................................................................................................... 98
Building Your Own Tree ................................................................................................................................100
Adding a Child Node into a Tree ....................................................................................................................100
LISP
Applying a Specified Function on Hash Table ................................................................................................106
27. STRUCTURES..................................................................................................................................119
Defining a Structure ......................................................................................................................................119
vi
LISP
Defining a Class Method................................................................................................................................135
Inheritance ....................................................................................................................................................136
vii
1. OVERVIEW
LISP stands for LISt Programming. John McCarthy invented LISP in 1958, shortly after
the development of FORTRAN. It was first implemented by Steve Russell on an IBM
704 computer. It is particularly suitable for Artificial Intelligence programs, as it
processes symbolic information efficiently.
Common LISP originated during the decade of 1980 to 1990, in an attempt to unify
the work of several implementation groups, as a successor of Maclisp like ZetaLisp and
New Implementation of LISP (NIL) etc.
It serves as a common language, which can be easily extended for specific
implementation. Programs written in Common LISP do not depend on machine-specific
characteristics, such as word length etc.
It is machine-independent
It is expression-based.
LISP
G2
AutoCad
Igor Engraver
Yahoo Store
2. ENVIRONMENT SETUP
LISP
CLISP is the GNU Common LISP multi-architechtural compiler used for setting up LISP
in Windows. The Windows version emulates Unix environment using MingW under
Windows. The installer takes care of this and automatically adds CLISP to the Windows
PATH variable.
You can get the latest CLISP for Windows at:
http://sourceforge.net/projects/clisp/files/latest/download
It creates a shortcut in the Start Menu by default, for the line-by-line interpreter.
3. PROGRAM STRUCTURE
LISP
Atoms
Lists
Strings
LISP
The evaluator defines syntax of LISP forms that are built from s-expressions.
LISP
This second level of evaluation defines a syntax that determines which sexpressions are LISP forms.
The evaluator works as a function that takes a valid LISP form as an argument
and returns a value. This is the reason why we put the LISP expression in
parenthesis, because we are sending the entire expression/form to the evaluator
as argument.
4. BASIC SYNTAX
LISP
atom
list
string
LISP
"Hello from 'Tutorials Point'! "
Adding Comments
The semicolon symbol (;) is used for indicating a comment line.
Example
(write-line "Hello World") ; greet the world
; tell them your whereabouts
(write-line "I am at 'Tutorials Point'! Learning LISP")
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result returned is:
Hello World
I am at 'Tutorials Point'! Learning LISP
Notable Points
The following important points are notable:
LISP represents a function call f(x) as (f x), for example cos(45) is written as
cos 45
LISP expressions are not case-sensitive. Means, cos 45 or COS 45 are same.
Numbers
The value nil, that stands for logical false, as well as an empty list.
LISP Forms
In the previous chapter, we mentioned that the evaluation process of LISP code takes
the following steps:
LISP
The evaluator defines syntax of LISP forms that are built from s-expressions.
This second level of evaluation defines a syntax that determines which sexpressions are LISP forms.
An atom
The evaluator works as a function that takes a valid LISP form as an argument and
returns a
value. This is
the reason
why
expression
in
LISP
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
single quote used, it inhibits evaluation
(* 2 3)
single quote not used, so expression evaluated
6
10
LISP
5. DATA TYPES
LISP data types can be categorized as:
Scalar types - numbers, characters, symbols etc.
Data structures - lists, vectors, bit-vectors, and strings.
Any variable can take any LISP object as its value, unless you declare it explicitly.
Although, it is not necessary to specify a data type for a LISP variable, however, it
helps in certain loop expansions, in method declarations and some other situations that
we will discuss in later chapters.
The data types are arranged into a hierarchy. A data type is a set of LISP objects and
many objects may belong to one such set.
The typep predicate is used for finding whether an object belongs to a specific type.
The type-of function returns the data type of a given object.
fixnum
package
simple-string
Atom
float
pathname
simple-vector
Bignum
function
random-state
single-float
Bit
hash-table
Ratio
standard-char
bit-vector
integer
Rational
stream
Character
keyword
readtable
string
[common]
list
sequence
[string-char]
compiled-function
long-float
short-float
symbol
Complex
nill
signed-byte
11
LISP
Cons
null
simple-array
unsigned-byte
double-float
number
simple-bit-vector
vector
Apart from these system-defined types, you can create your own data types. When a
structure type is defined using defstruct function, the name of the structure type
becomes a valid type symbol.>/p>
Example 1
Create new source code file named main.lisp and type the following code in it:
(setq x 10)
(setq y 34.567)
(setq ch nil)
(setq n 123.78)
(setq bg 11.0e+4)
(setq r 124/2)
(print x)
(print y)
(print n)
(print ch)
(print bg)
(print r)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result returned is:
10
34.567
123.78
NIL
110000.0
62
12
LISP
Example 2
Next let us check the types of the variables used in the previous example. Create new
source code file named main.lisp and type the following code in it:
(setq x 10)
(setq y 34.567)
(setq ch nil)
(setq n 123.78)
(setq bg 11.0e+4)
(setq r 124/2)
(print (type-of x))
(print (type-of y))
(print (type-of n))
(print (type-of ch))
(print (type-of bg))
(print (type-of r))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the resultis:
(INTEGER 0 281474976710655)
SINGLE-FLOAT
SINGLE-FLOAT
NULL
SINGLE-FLOAT
(INTEGER 0 281474976710655)
13
6. MACROS
LISP
Defining a Macro
In LISP, a named macro is defined using another macro named defmacro. Syntax for
defining a macro is:
(defmacro macro-name (parameter-list)
"Optional documentation string."
body-form)
The macro definition consists of the name of the macro, a parameter list, an optional
documentation string, and a body of LISP expressions that defines the job to be
performed by the macro.
Example
Let us write a simple macro named setTo10, which takes a number and sets its value
to 10.
Create new source code file named main.lisp and type the following code in it:
defmacro setTo10(num)
(setq num 10)(print num))
(setq x 25)
(print x)
(setTo10 x)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
25
10
14
7. VARIABLES
LISP
In LISP, each variable is represented by a symbol. The name of the variable is the
name of the symbol and it is stored in the storage cell of the symbol.
Global Variables
Global variables are generally declared using the defvar construct. Global variables
have permanent values throughout the LISP system and remain in effect until new
values are specified.
Example
(defvar x 234)
(write x)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
234
As there is no type declaration for variables in LISP, you need to specify a value for a
symbol directly with the setq construct.
Example
->(setq x 10)
The above expression assigns the value 10 to the variable x. You can refer to the
variable using the symbol itself as an expression.
The symbol-value function allows you to extract the value stored at the symbol
storage place.
Example
Create new source code file named main.lisp and type the following code in it:
(setq x 10)
(setq y 20)
(format t "x = ~2d y = ~2d ~%" x y)
(setq x 100)
(setq y 200)
15
LISP
(format t "x = ~2d y = ~2d" x y)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
x = 10 y = 20
x = 100 y = 200
Local Variables
Local variables are defined within a given procedure. The parameters named as
arguments within a function definition are also local variables. Local variables are
accessible only within the respective function.
Like the global variables, local variables can also be created using the setq construct.
There are two other constructs - let and prog for creating local variables.
The let construct has the following syntax:
(let ((var1
val1) (var2
val2).. (varn
valn))<s-expressions>)
Where var1, var2,,varn are variable names and val1, val2,, valn are the initial
values assigned to the respective variables.
When let is executed, each variable is assigned the respective value and at last, the sexpression is evaluated. The value of the last expression evaluated is returned.
If you do not include an initial value for a variable, the variable is assigned to nil.
Example
Create new source code file named main.lisp and type the following code in it:
(let ((x 'a)
(y 'b)
(z 'c))
(format t "x = ~a y = ~a z = ~a" x y z))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
x = A y = B z = C
The prog construct also has the list of local variables as its first argument, which is
followed by the body of the prog, and any number of s-expressions.
16
LISP
The prog function executes the list of s-expressions in sequence and returns nil unless
it encounters a function call named return. Then the argument of the return function
is evaluated and returned.
Example
Create new source code file named main.lisp and type the following code in it:
(prog ((x '(a b c))
(y '(1 2 3))
(z '(p q 10)))
(format t "x = ~a y = ~a z = ~a" x y z))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
x = (A B C) y = (1 2 3) z = (P Q 10)
17
8. CONSTANTS
LISP
In LISP, constants are variables that never change their values during program
execution. Constants are declared using the defconstant construct.
Example
The following example shows declaring a global constant PI and later using this value
inside a function named area-circle that calculates the area of a circle. The defun
construct is used for defining a function, we will look into it in the 'Functions' chapter.
Create a new source code file named main.lisp and type the following code in it:
(defconstant PI 3.141592)
(defun area-circle(rad)
(terpri)
(format t "Radius: ~5f" rad)
(format t "~%Area: ~10f" (* PI rad rad)))
(area-circle 10)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
Radius:
Area:
10.0
314.1592
18
LISP
9. OPERATORS
Arithmetic Operations
Comparison Operations
Logical Operations
Bitwise Operations
Arithmetic Operations
The following table shows all the arithmetic operators supported by LISP. Assume
variable A = 10 and variable B = 20 then:
Operator
Description
Example
(+ A B) gives 30
(- A B) gives-10
(* A B) gives 200
(/ B A) gives 2
mod,rem
incf
decf
operator
increases
integer
(mod B A )gives 0
(incf A 3) gives 13
(decf A 4) gives 9
19
LISP
Example
Create a new source code file named main.lisp and type the following code in it:
(setq a 10)
(setq b 20)
(format t "~% A + B = ~d" (+ a b))
(format t "~% A - B = ~d" (- a b))
(format t "~% A x B = ~d" (* a b))
(format t "~% B / A = ~d" (/ b a))
(format t "~% Increment A by 3 = ~d" (incf a 3))
(format t "~% Decrement A by 4 = ~d" (decf a 4))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
A + B = 30
A - B = -10
A x B = 200
B / A = 2
Increment A by 3 = 13
Decrement A by 4 = 9
Comparison Operations
Following table shows all the relational operators supported by LISP that compares
between numbers. However unlike relational operators in other languages, LISP
comparison operators may take more than two operands and they work on numbers
only.
Assume variable A = 10 and variable B = 20, then:
Operator
Description
Example
/=
20
LISP
>
<
>=
(< A B) is true.
(>= A B) is not
true.
max
min
20
20
Example
Create a new source code file named main.lisp and type the following code in it:
(setq a 10)
(setq b 20)
(format t "~% A = B is ~a" (= a b))
(format t "~% A /= B is ~a" (/= a b))
(format t "~% A > B is ~a" (> a b))
(format t "~% A < B is ~a" (< a b))
(format t "~% A >= B is ~a" (>= a b))
(format t "~% A <= B is ~a" (<= a b))
(format t "~% Max of A and B is ~d" (max a b))
(format t "~% Min of A and B is ~d" (min a b))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
A = B is NIL
A /= B is T
21
LISP
A > B is NIL
A < B is T
A >= B is NIL
A <= B is T
Max of A and B is 20
Min of A and B is 10
Description
It
takes
any
number
of
Example
arguments.
The
or
not
takes
any
number
of
arguments.
The
(and A B) returns
NIL.
(or A B) returns 5.
(not A) returns T.
Example
Create a new source code file named main.lisp and type the following code in it:
(setq a 10)
(setq b 20)
(format t "~% A and B is ~a" (and a b))
(format t "~% A or B is ~a" (or a b))
(format t "~% not A is ~a" (not a))
(terpri)
(setq a nil)
22
LISP
(setq b 5)
(format t "~% A and B is ~a" (and a b))
(format t "~% A or B is ~a" (or a b))
(format t "~% not A is ~a" (not a))
(terpri)
(setq a nil)
(setq b 0)
(format t "~% A and B is ~a" (and a b))
(format t "~% A or B is ~a" (or a b))
(format t "~% not A is ~a" (not a))
(terpri)
(setq a 10)
(setq b 0)
(setq c 30)
(setq d 40)
(format t "~% Result of and operation on 10, 0, 30, 40 is ~a" (and a b c d))
(format t "~% Result of and operation on 10, 0, 30, 40 is ~a" (or a b c d))
(terpri)
(setq a 10)
(setq b 20)
(setq c nil)
(setq d 40)
(format t "~% Result of and operation on 10, 20, nil, 40 is ~a" (and a b c d))
(format t "~% Result of and operation on 10, 20, nil, 40 is ~a" (or a b c d))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
A and B is 20
A or B is 10
not A is NIL
A and B is NIL
A or B is 5
not A is T
23
LISP
A and B is NIL
A or B is 0
not A is T
p and q
p or q
p xor q
Assume if A = 60; and B = 13; now in binary format they are represented as:
A = 0011 1100
B = 0000 1101
----------------A and B = 0000 1100
A or B = 0011 1101
A xor B = 0011 0001
not A
= 1100 0011
24
LISP
The Bitwise operators supported by LISP are listed in the following table. Assume
variable A = 60 and variable B = 13, then:
Operator
Description
Example
operation.
This returns the bit-wise logical INCLUSIVE OR
logior
(logior a b) gives 61
operation.
This returns the bit-wise logical EXCLUSIVE OR
logxor
(logxor a b) gives 49
operation.
This returns the bit-wise NOT of its arguments.
lognor
logeqv
Example
Create a new source code file named main.lisp and type the following code in it:
(setq a 60)
(setq b 13)
(format t "~% BITWISE AND of a and b is ~a" (logand a b))
(format t "~% BITWISE INCLUSIVE OR of a and b is ~a" (logior a b))
(format t "~% BITWISE EXCLUSIVE OR of a and b is ~a" (logxor a b))
(format t "~% A NOT B is ~a" (lognor a b))
(format t "~% A EQUIVALANCE B is ~a" (logeqv a b))
25
LISP
(terpri)
(terpri)
(setq a 10)
(setq b 0)
(setq c 30)
(setq d 40)
(format t "~% Result of bitwise and operation on 10, 0, 30, 40 is ~a" (logand
a b c d))
(format t "~% Result of bitwise or operation on 10, 0, 30, 40 is ~a" (logior
a b c d))
(format t "~% Result of bitwise xor operation on 10, 0, 30, 40 is ~a" (logxor
a b c d))
(format t "~% Result of bitwise equivalence operation on 10, 0, 30, 40 is ~a"
(logeqv a b c d))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
BITWISE AND of a and b is 12
BITWISE INCLUSIVE OR of a and b is 61
BITWISE EXCLUSIVE OR of a and b is 49
A NOT B is -62
A EQUIVALANCE B is -50
26
LISP
Decision making structures require the programmer to specify one or more conditions
to be evaluated or tested by the program, along with a statement or statements to be
executed if the condition is determined to be true, and optionally, other statements to
be executed if the condition is determined to be false.
The following diagram shows the general form of a typical decision making structure
found in most of the programming languages:
LISP provides following types of decision making constructs. Click the following links
to check their detail.
Construct
Description
This construct is used for checking multiple test-action clauses.
cond
if
27
LISP
consequent action(s). If the test clause evaluates to true, then
the test action is executed. Otherwise, the consequent clause
is evaluated.
In simplest form it is followed by a test clause, and a test
when
action. If the test clause evaluates to true, then the test action
is executed. Otherwise, the consequent clause is evaluated.
This construct implements multiple test-action clauses such as
cond construct. However, it evaluates a key form and allows
case
(test1
action1)
(test2
action2)
...
(testn
actionn))
Each clause within the cond statement consists of a conditional test and an action to
be performed.
If the first test following the cond, i.e. test1, is evaluated to be true, then the
corresponding action part, i.e. action1 is executed. Further, its value is returned and
the rest of the clauses are skipped.
If test1 evaluates to be nil, then program control moves to the second clause without
executing action1, and the same process is followed.
If none of the test conditions are evaluated to be true, then the cond statement
returns nil.
Example
Create a new source code file named main.lisp and type the following code in it:
(setq a 10)
(cond ((> a 20)
(format t "~% a is less than 20"))
28
LISP
(t (format t "~% value of a is ~d " a)))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
value of a is 10
Note that the t in the second clause ensures that the last action is performed if none
other is fulfilled.
The if Construct
The if macro is followed by a test clause that evaluates to t or nil. If the test clause is
evaluated to the t, then the action following the test clause is executed. If it is nil, then
the next clause is evaluated.
Syntax for if:
(if (test-clause) (<action1) (action2))
Example 1
Create a new source code file named main.lisp and type the following code in it:
(setq a 10)
(if (> a 20)
(format t "~% a is less than 20"))
(format t "~% value of a is ~d " a)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
value of a is 10
Example 2
The if clause can be followed by an optional then clause:
Create a new source code file named main.lisp and type the following code in it:
(setq a 10)
(if (> a 20)
then (format t "~% a is less than 20"))
(format t "~% value of a is ~d " a)
29
LISP
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
a is less than 20
value of a is 10
Example 3
You can also create an if-then-else type statement using the if clause.
Create a new source code file named main.lisp and type the following code in it:
(setq a 100)
(if (> a 20)
(format t "~% a is greater than 20")
(format t "~% a is less than 20"))
(format t "~% value of a is ~d " a)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
a is greater than 20
value of a is 100
30
LISP
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
a is greater than 20
value of a is 100
ThecaseConstruct
The case construct implements multiple test-action clauses such as the cond construct.
However, it evaluates a key form and allows multiple action clauses based on the
evaluation of that key form.
Syntax for case macro:
The template for CASE is:
(case
(keyform)
((key1)
(action1
action2 ...) )
((key2)
(action1
action2 ...) )
(action1
action2 ...) ))
...
((keyn)
Example
Create a new source code file named main.lisp and type the following code in it:
(setq day 4)
(case day
(1 (format t "~% Monday"))
(2 (format t "~% Tuesday"))
(3 (format t "~% Wednesday"))
(4 (format t "~% Thursday"))
(5 (format t "~% Friday"))
(6 (format t "~% Saturday"))
(7 (format t "~% Sunday")))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
Thursday
31
11. LOOPS
LISP
Consider a situation, where you need to execute a block of code numbers of times. A
loop statement allows us to execute a statement or group of statements multiple
times. The following diagram shows the general form of a loop statement in most of
the programming languages:
Description
It is the simplest form of iteration provided by LISP. In its simplest form,
Loop
loop for
do
dotimes
32
LISP
dolist
33
LISP
It allows you to:
specify expression(s), and expressions for doing some job before exiting the
loop
34
LISP
13
14
15
16
17
18
19
20
Example 3
Create a new source code file named main.lisp and type the following code in it:
(loop for x from 1 to 20
if(evenp x)
do (print x)
)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
2
4
6
8
10
12
14
16
18
20
The do Construct
The do construct is also used for performing iteration using LISP. It provides a
structured form of iteration.
35
LISP
Syntax for do:
(do (variable1
value1
(variable2
value2
(variable3
value3
updated-value1)
updated-value2)
updated-value3)
...
(test
return-value)
(s-expressions))
The initial values of each variable is evaluated and bound to the respective variable.
The updated value in each clause corresponds to an optional update statement that
specifies how the values of the variables will be updated with each iteration.
After each iteration, the test is evaluated.If it returns a non-nil or true, the returnvalue is evaluated and returned.The last s-expression(s) is optional. If present, they
are executed after every iteration, until the test value returns true.
Example
Create a new source code file named main.lisp and type the following code in it:
(do ((x 0 (+ 2 x))
(y 20 ( - y 2)))
((= x y)(- x y))
(format t "~% x = ~d
y = ~d" x y))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
x = 0
y = 20
x = 2
y = 18
x = 4
y = 16
x = 6
y = 14
x = 8
y = 12
36
LISP
(dotimes (n 11)
(print n) (prin1 (* n n)))
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
0 0
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
10 100
37
LISP
Number: 9 Square: 81
38
LISP
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and
the result is:
ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK
ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK
5
LEFT-INNER-BLOCK
LEAVING-OUTER-BLOCK
39
12. FUNCTIONS
LISP
40
LISP
Example 2
Let us define and call a function that calculates the area of a circle when the radius of
the circle is given as an argument.
Create a new source code file named main.lisp and type the following code in it:
(defun area-circle(rad)
"Calculates area of a circle with given radius"
(terpri)
(format t "Radius: ~5f" rad)
(format t "~%Area: ~10f" (* 3.141592 rad rad)))
(area-circle 10)
Note:
You can provide an empty list as parameters, which means the function takes
no arguments, the list is empty, written as ().
function
and
can
be
obtained
using
The body of the function may consist of any number of LISP expressions.
The value of the last expression in the body is returned as the value of the
function.
You can also return a value from the function using the return-from special
operator.
Optional Parameters
You can define a function with optional parameters. To do this, you need to put the
symbol &optional before the names of the optional parameters.
Let us write a function that displays the parameters it received.
Example
Create a new source code file named main.lisp and type the following code in it:
(defun show-members (a b &optional c d) (write (list a b c d)))
(show-members 1 2 3)
41
LISP
(terpri)
(show-members 'a 'b 'c 'd)
(terpri)
(show-members 'a 'b)
(terpri)
(show-members 1 2 3 4)
When you execute the code, it returns the following result:
(1 2 3 NIL)
(A B C D)
(A B NIL NIL)
(1 2 3 4)
Note that the parameter c and d are the optional parameters in the above example.
Rest Parameters
Some functions need to take a variable number of arguments.
For example, the format function we are using needs two arguments, the stream and
the control string. However, after the string, it needs a variable number of arguments
depending upon the number of values to be displayed in the string. Similarly, the +
function, or the * function may also take a variable number of arguments. You can
provide for such variable number of parameters using the symbol &rest.
The following example illustrates the concept:
Example
Create a new source code file named main.lisp and type the following code in it:
(defun show-members (a b &rest values) (write (list a b values)))
(show-members 1 2 3)
(terpri)
(show-members 'a 'b 'c 'd)
(terpri)
(show-members 'a 'b)
(terpri)
(show-members 1 2 3 4)
(terpri)
42
LISP
(show-members 1 2 3 4 5 6 7 8 9)
When you execute the code, it returns the following result:
(1 2 (3))
(A B (C D))
(A B NIL)
(1 2 (3 4))
(1 2 (3 4 5 6 7 8 9))
Keyword Parameters
Keyword parameters allow you to specify which values go with which particular
parameter. They are indicated using &key symbol. When you send the values to the
function, you must precede the values with parameter-name. The following example
illustrates the concept:
Example
Create a new source code file named main.lisp and type the following code in it:
(defun show-members (&key a b c d ) (write (list a b c d)))
(show-members :a 1 :c 2 :d 3)
(terpri)
(show-members :a 'p :b 'q :c 'r :d 's)
(terpri)
(show-members :a 'p :d 'q)
(terpri)
(show-members :a 1 :b 2)
When you execute the code, it returns the following result:
(1 NIL 2 3)
(P Q R S)
(P NIL NIL Q)
(1 2 NIL NIL)
43
LISP
Example 1
Create a new source code file named main.lisp and type the following code in it:
(defun add-all(a b c d)
(+ a b c d))
(setq sum (add-all 10 20 30 40))
(write sum)
(terpri)
(write (add-all 23.4 56.7 34.9 10.0))
When you execute the code, it returns the following result:
100
125.0
However, you can use the return-from special operator to immediately return any
value from the function.
Example 2
Create a new source code file named main.lisp and type the following code in it:
(defun myfunc (num)
(return-from myfunc 10)
num)
(write (myfunc 20))
When you execute the code, it returns the following result:
10
Change the code a little:
(defun myfunc (num)
(return-from myfunc 10)
write num)
(write (myfunc 20))
It still returns:
10
44
LISP
Lambda Functions
At times you may need a function in only one place in your program and the function
is so trivial that you may not give it a name, or may not like to store it in the symbol
table, and would rather write an unnamed or anonymous function.
LISP allows you to write anonymous functions that are evaluated only when they are
encountered in the program. These functions are called Lambda functions.
You can create such functions using the lambda expression. The syntax for the lambda
expression is as follows:
(lambda (parameters) body)
A lambda form cannot be evaluated and it must appear only where LISP expects to
find a function.
Example
Create a new source code file named main.lisp and type the following code in it:
(write ((lambda (a b c x)
(+ (* a (* x x)) (* b x) c))
4 2 9 3))
When you execute the code, it returns the following result:
51
Mapping Functions
Mapping functions are a group of functions that could be applied successively to one
or more lists of elements. The results of applying these functions to a list are placed in
a new list and that new list is returned.
For example, the mapcar function processes successive elements of one or more lists.
The first argument of the mapcar function is a function and the remaining arguments
are the list(s), to which the function is applied. The argument function is applied to the
successive elements and that results into a newly constructed list. If the argument lists
are not equal in length, then the process of mapping stops upon reaching the end of
the shortest list. The resulting list will have the same number of elements as the
shortest input list.
45
LISP
Example 1
Let us start with a simple example. Add the number 1 to each element of the list ( 23,
34, 45, 56, 67, 78, 89).
Create a new source code file named main.lisp and type the following code in it:
(write (mapcar '1+
'(23 34 45 56 67 78 89)))
46
13. PREDICATES
LISP
Predicates are functions that test their arguments for some specific conditions and
returns nil if the condition is false, or some non-nil value if the condition is true.
The following table shows some of the most commonly used predicates:
Predicate
atom
equal
eq
Description
It takes one argument and returns t if the argument is an atom, nil
otherwise.
It takes two arguments and returns t if they are structurally equal
or nil otherwise.
It takes two arguments and returns t if they are same identical objects,
sharing the same memory location, or nil otherwise.
It takes two arguments and returns t if both arguments are equal, or they
eql
are numbers of the same type with the same value, or they are character
objects that represent the same character, or nil otherwise.
evenp
oddp
zerop
null
listp
47
LISP
It takes one or more arguments and returns t if either there is a single
greaterp
lessp
numberp
symbolp
integerp
rationalp
floatp
realp
complexp
characterp
stringp
arrayp
packagep
48
LISP
Example 1
Create a new source code file named main.lisp and type the following code in it:
(write (atom 'abcd))
(terpri)
(write (equal 'a 'b))
(terpri)
(write (evenp 10))
(terpri)
(write (evenp 7 ))
(terpri)
(write (oddp 7 ))
(terpri)
(write (zerop 0.0000000001))
(terpri)
(write (eq 3 3.0 ))
(terpri)
(write (equal 3 3.0 ))
(terpri)
(write (null nil ))
49
LISP
Example 2
Create a new source code file named main.lisp and type the following code in it:
(defun factorial (num)
(cond ((zerop num) 1)
(t ( * num (factorial (- num 1))))))
(setq n 6)
(format t "~% Factorial ~d is: ~d" n (factorial n))
When you execute the code, it returns the following result:
Factorial 6 is: 720
50
14. NUMBERS
LISP
Common LISP defines several kinds of numbers. The number data type includes
various kinds of numbers supported by LISP. The following numeric data types are
supported by LISP:
Integers
Ratios
Floating-point numbers
Complex numbers
The following diagram shows the number hierarchy and various numeric data types
available in LISP:
51
LISP
Description
type
fixnum
This data type represents integers which are not too large. Their values
range from
-215 to 215-1. (it is machine-dependent)
bignum
These are very large numbers with size limited by the amount of memory
allocated for LISP, they are not fixnum numbers.
This represents the ratio of two numbers in the numerator/denominator
ratio
form. The / function always produces the result in ratios, with integer
arguments.
float
It represents non-integer numbers. There are four float data types with
increasing precision.
complex
It represents complex numbers, which are denoted by #c. The real and
imaginary parts could be both either rational or floating point numbers.
Example
Create a new source code file named main.lisp and type the following code in it:
(write (/ 1 2))
(terpri)
(write ( + (/ 1 2) (/ 3 4)))
(terpri)
(write ( + #c( 1 2) #c( 3 -4)))
When you execute the code, it returns the following result:
1/2
5/4
#C(4 -2)
52
LISP
Number Functions
The following table describes some commonly used numeric functions:
Function
Description
+, -, *, /
sin,
cos,
tan,
sinh, cosh,
tanh, acosh,
asinh, atanh
exp
expt
sqrt
log
conjugate
abs
gcd
lcm
isqrt
floor,
ceiling, ratio, ceiling chooses the smaller integer that is larger than
truncate, round
ratio, truncate chooses the integer of the same sign as ratio with the
largest absolute value that is less than absolute value of ratio,
and roundchooses an integer that is closest to ratio.
53
LISP
ffloor, fceiling,
ftruncate,
fround
Does the same as above, but returns the quotient as a floating point
number.
mod, rem
float
rational,
rationalize
numerator,
denominator
realpart,
imagpart
Example
Create a new source code file named main.lisp and type the following code in it:
(write (/ 45 78))
(terpri)
(write (floor 45 78))
(terpri)
(write (/ 3456 75))
(terpri)
(write (floor 3456 75))
(terpri)
(write (ceiling 3456 75))
(terpri)
(write (truncate 3456 75))
(terpri)
(write (round 3456 75))
(terpri)
(write (ffloor 3456 75))
(terpri)
(write (fceiling 3456 75))
54
LISP
(terpri)
(write (ftruncate 3456 75))
(terpri)
(write (fround 3456 75))
(terpri)
(write (mod 3456 75))
(terpri)
(setq c (complex 6 7))
(write c)
(terpri)
(write (complex 5 -9))
(terpri)
(write (realpart c))
(terpri)
(write (imagpart c))
When you execute the code, it returns the following result:
15/26
0
1152/25
46
47
46
46
46.0
47.0
46.0
46.0
6
#C(6 7)
#C(5 -9)
6
7
55
15. CHARACTERS
LISP
In LISP, characters are represented as data objects of type character. You can denote
a character object preceding #\ before the character itself. For example, #\a means
the character a.
Space and other special characters can be denoted by preceding #\ before the name
of the character. For example, #\SPACE represents the space character.
The following example demonstrates this:
Example
Create a new source code file named main.lisp and type the following code in it:
(write 'a)
(terpri)
(write #\a)
(terpri)
(write-char #\a)
(terpri)
(write-char 'a)
When you execute the code, it returns the following result:
A
#\a
a
*** - WRITE-CHAR: argument A is not a character
Special Characters
Common LISP allows using the following special characters in your code. They are
called the semi-standard characters.
#\Backspace
#\Tab
#\Linefeed
56
LISP
#\Page
#\Return
#\Rubout
Case-
Sensitive
Functions
Insensitive
Functions
char=
char/=
char-equal
char-notequal
Description
char<
char-lessp
char>
char-greaterp
char<=
char-notgreaterp
char>=
57
LISP
Example
Create a new source code file named main.lisp and type the following code in it:
; case-sensitive comparison
(write (char= #\a #\b))
(terpri)
(write (char= #\a #\a))
(terpri)
(write (char= #\a #\A))
(terpri)
;case-insensitive comparision
(write (char-equal #\a #\A))
(terpri)
(write (char-equal #\a #\b))
(terpri)
(write (char-lessp #\a #\b #\c))
(terpri)
(write (char-greaterp #\a #\b #\c))
When you execute the code, it returns the following result:
NIL
T
NIL
T
NIL
T
NIL
58
16. ARRAYS
LISP
LISP allows you to define single or multiple-dimension arrays using the makearray function. An array can store any LISP object as its elements.
All arrays consist of contiguous memory locations. The lowest address corresponds to
the first element and the highest address corresponds to the last element.
59
LISP
(setf (aref my-array 2) 45)
(setf (aref my-array 3) 10)
(setf (aref my-array 4) 20)
(setf (aref my-array 5) 17)
(setf (aref my-array 6) 25)
(setf (aref my-array 7) 19)
(setf (aref my-array 8) 67)
(setf (aref my-array 9) 30)
(write my-array)
When you execute the code, it returns the following result:
#(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)
#(25 23 45 10 20 17 25 19 67 30)
Example 2
Let us create a 3-by-3 array.
Create a new source code file named main.lisp and type the following code in it:
(setf x (make-array '(3 3)
:initial-contents '((0 1 2 ) (3 4 5) (6 7 8))))
(write x)
When you execute the code, it returns the following result:
#2A((0 1 2) (3 4 5) (6 7 8))
Example 3
Create a new source code file named main.lisp and type the following code in it:
(setq a (make-array '(4 3)))
(dotimes (i 4)
(dotimes (j 3)
(setf (aref a i j) (list i 'x j '= (* i j)))))
(dotimes (i 4)
(dotimes (j 3)
(print (aref a i j))))
When you execute the code, it returns the following result:
60
LISP
(0 X 0 = 0)
(0 X 1 = 0)
(0 X 2 = 0)
(1 X 0 = 0)
(1 X 1 = 1)
(1 X 2 = 2)
(2 X 0 = 0)
(2 X 1 = 2)
(2 X 2 = 4)
(3 X 0 = 0)
(3 X 1 = 3)
(3 X 2 = 6)
Syntax for the make-array Function
The make-array function takes many other arguments. Let us look at the complete
syntax of this function:
make-array dimensions :element-type :initial-element :initial-contents
:adjustable :fill-pointer :displaced-to :displaced-index-offset
Apart from the dimensions argument, all other arguments are keywords. The following
table provides brief description of the arguments.
Argument
dimensions
:elementtype
Description
It gives the dimensions of the array. It is a number for one-dimensional
array, and a list for multi-dimensional array.
:initial-
Initial elements value. It makes an array with all the elements initialized
element
to a particular value.
:initialcontent
61
LISP
It helps in creating a resizable (or adjustable) vector whose underlying
:adjustable
:fill-pointer
:displaced-to element type. The :displaced-to option may not be used with the
:initial-element or :initial-contents option. This argument defaults to
nil.
:displacedindex-offset
Example 4
Create a new source code file named main.lisp and type the following code in it:
(setq myarray (make-array '(3 2 3)
:initial-contents
'(((a b c) (1 2 3))
((d e f) (4 5 6))
((g h i) (7 8 9))
)))
(setq array2 (make-array 4 :displaced-to myarray
:displaced-index-offset 2))
(write myarray)
(terpri)
(write array2)
When you execute the code, it returns the following result:
#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#(C 1 2 3)
62
LISP
(setq myarray (make-array '(3 2 3)
:initial-contents
'(((a b c) (1 2 3))
((d e f) (4 5 6))
((g h i) (7 8 9))
)))
(setq array2 (make-array '(3 2) :displaced-to myarray
:displaced-index-offset 2))
(write myarray)
(terpri)
(write array2)
When you execute the code, it returns the following result:
#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((C 1) (2 3) (D E))
Let us change the displaced index offset to 5:
(setq myarray (make-array '(3 2 3)
:initial-contents
'(((a b c) (1 2 3))
((d e f) (4 5 6))
((g h i) (7 8 9))
)))
(setq array2 (make-array '(3 2) :displaced-to myarray
:displaced-index-offset 5))
(write myarray)
(terpri)
(write array2)
When you execute the code, it returns the following result:
#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((3 D) (E F) (4 5))
Example 5
Create a new source code file named main.lisp and type the following code in it:
63
LISP
;a one dimensional array with 5 elements,
;initail value 5
(write (make-array 5 :initial-element 5))
(terpri)
;two dimensional array, with initial element a
(write (make-array '(2 3) :initial-element 'a))
(terpri)
;an array of capacity 14, but fill pointer 5, is 5
(write(length (make-array 14 :fill-pointer 5)))
(terpri)
;however its length is 14
(write (array-dimensions (make-array 14 :fill-pointer 5)))
(terpri)
; a bit array with all initial elements set to 1
(write(make-array 10 :element-type 'bit :initial-element 1))
(terpri)
; a character array with all initial elements set to a
; is a string actually
(write(make-array 10 :element-type 'character :initial-element #\a))
(terpri)
; a two dimensional array with initial values a
(setq myarray (make-array '(2 2) :initial-element 'a :adjustable t))
(write myarray)
(terpri)
;readjusting the array
(adjust-array myarray '(1 3) :initial-element 'b)
(write myarray)
When you execute the code, it returns the following result:
#(5 5 5 5 5)
#2A((A A A) (A A A))
5
(14)
#*1111111111
"aaaaaaaaaa"
64
LISP
#2A((A A) (A A))
#2A((A A B))
65
LISP
17. STRINGS
Strings in Common LISP are vectors, i.e., one-dimensional array of characters. String
literals are enclosed in double quotes. Any character supported by the character set
can be enclosed within double quotes to make a string, except the double quote
character (") and the escape character (\). However, you can include these by escaping
them with a backslash (\).
Example
Create a new source code file named main.lisp and type the following code in it:
(write-line "Hello World")
(write-line "Welcome to Tutorials Point")
;escaping the double quote character
(write-line "Welcome to \"Tutorials Point\"")
When you execute the code, it returns the following result:
Hello World
Welcome to Tutorials Point
Welcome to "Tutorials Point"
Case-
Sensitive
insensitive
Functions
Functions
string=
string-equal
Description
66
LISP
Checks if the values of the operands are all different
string/=
string<
string-lessp
string>
string-greaterp
string<=
string-notgreaterp
Checks
if
the
values
of
the
operands
are
of
the
operands
are
monotonically decreasing.
Checks
if
the
values
monotonically increasing.
Checks if the value of any left operand is greater
than or equal to the value of next right operand, if
yes then condition becomes true.
Checks if the value of any left operand is less than
string>=
Example
Create a new source code file named main.lisp and type the following code in it:
; case-sensitive comparison
(write (string= "this is test" "This is test"))
(terpri)
(write (string> "this is test" "This is test"))
(terpri)
(write (string< "this is test" "This is test"))
(terpri)
;case-insensitive comparision
(write (string-equal "this is test" "This is test"))
(terpri)
(write (string-greaterp "this is test" "This is test"))
(terpri)
(write (string-lessp "this is test" "This is test"))
(terpri)
;checking non-equal
(write (string/= "this is test" "this is Test"))
67
LISP
(terpri)
(write (string-not-equal "this is test" "This is test"))
(terpri)
(write (string/= "lisp" "lisping"))
(terpri)
(write (string/= "decent" "decency"))
When you execute the code, it returns the following result:
NIL
0
NIL
T
NIL
NIL
8
NIL
4
5
Description
string-upcase
string-downcase
string-capitalize
68
LISP
Example
Create a new source code file named main.lisp and type the following code in it:
(write-line (string-upcase "a big hello from tutorials point"))
(write-line (string-capitalize "a big hello from tutorials point"))
When you execute the code, it returns the following result:
A BIG HELLO FROM TUTORIALS POINT
A Big Hello From Tutorials Point
Trimming Strings
The following table describes the string trimming functions:
Function
Description
It takes a string of character(s) as first argument and a string as the
string-trim second argument and returns a substring where all characters that are in
the first argument are removed off the argument string.
String-lefttrim
Stringright-trim
Example
Create a new source code file named main.lisp and type the following code in it:
(write-line (string-trim " " "
"))
"))
"))
"))
69
LISP
When you execute the code, it returns the following result:
a big hello from tutorials point
a big hello from tutorials point
a big hello from tutorials point
big hello from tutorials point
Extracting Sub-string
The subseq function returns a sub-string (as a string is also a sequence) starting at a
particular index and continuing up to a particular ending index or the end of the string.
70
LISP
Reversing a String
The reverse function reverses a string.
Example
Create a new source code file named main.lisp and type the following code in it:
(write-line (reverse "Are we not drawn onward, we few, drawn onward to new
era"))
When you execute the code, it returns the following result:
are wen ot drawno nward ,wef ew ,drawno nward ton ew erA
Concatenating Strings
The concatenate function concatenates two strings. This is generic sequence function
and you must provide the result type as the first argument.
Example
Create a new source code file named main.lisp and type the following code in it:
71
LISP
(write-line (concatenate 'string "Are we not drawn onward, " "we few, drawn
onward to new era"))
When you execute the code, it returns the following result:
Are we not drawn onward, we few, drawn onward to new era
72
18. SEQUENCES
LISP
Sequence is an abstract data type in LISP. Vectors and lists are the two concrete
subtypes of this data type. All the functionalities defined on sequence data type are
actually applied on all vectors and list types.
In this chapter, we will discuss most commonly used functions on sequences.
Before starting on various ways of manipulating sequences i.e., vectors and lists, let
us have a look at the list of all available functions.
Creating a Sequence
The function make-sequence allows you to create a sequence of any type. The syntax
for this function is:
make-sequence sqtype sqsize &key :initial-element
It creates a sequence of type sqtype and of length sqsize.
You may optionally specify some value using the :initial-element argument, then each
of the elements is initialized to this value.
Example
Create a new source code file named main.lisp and type the following code in it:
(write (make-sequence '(vector float)
10
:initial-element 1.0))
When you execute the code, it returns the following result:
#(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)
Description
It allows access to individual elements through an integer index.
73
LISP
length
subseq
copy-seq
fill
replace
count
reverse
nreverse
concatenate
position
find
It takes an item and a sequence and returns the number of times the
item appears in the sequence.
It returns a sequence containing the same elements of the argument
but in reverse order.
It returns the same sequence containing the same elements as
sequence but in reverse order.
It creates a new sequence containing the concatenation of any number
of sequences.
It takes an item and a sequence and returns the index of the item in
the sequence or nil.
It takes an item and a sequence. It finds the item in the sequence and
returns it. If the item is not found, then it returns nil.
sort
merge
map
74
LISP
It takes a predicate as an argument and iterates over the argument
some
sequence, and returns the first non-NIL value returned by the predicate
or returns false if the predicate is never satisfied.
It takes a predicate as an argument and iterates over the argument
every
notany
notevery
sequence, and returns true as soon as the predicate fails or false if the
predicate is always satisfied.
It maps over a single sequence, applying a two-argument function first
reduce
to the first two elements of the sequence and then to the value returned
by the function and subsequent elements of the sequence.
search
remove
delete
substitute
same kind as the argument sequence that has the same elements
except the item.
It takes a new item, an existing item, and a sequence and returns a
sequence with instances of the existing item replaced with the new item.
It takes a new item, an existing item, and a sequence and returns the
nsubstitute
same sequence with instances of the existing item replaced with the
new item.
mismatch
It takes two sequences and returns the index of the first pair of
mismatched elements.
75
LISP
:test
:key
:start
:end
:from-end
:count
Meaning
Default
Value
EQL
NIL
NIL
NIL
We have just discussed various functions and keywords that are used as arguments in
the functions working on sequences. In the next chapters, we will see how to use these
functions, with examples.
76
LISP
When you execute the code, it returns the following result:
5
D
Modifying Sequences
Some sequence functions allows iterating through the sequence and perform some
operations like, searching, removing, counting or filtering specific elements without
writing explicit loops.
The following example demonstrates this:
Example 1
Create a new source code file named main.lisp and type the following code in it:
(write (count 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (substitute 10 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (find 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (position 5 '(1 5 6 7 8 9 2 7 3 4 5)))
When you execute the code, it returns the following result:
2
(1 6 7 8 9 2 7 3 4)
(1 6 7 8 9 2 7 3 4)
(1 5 6 10 8 9 2 10 3 4 5)
7
1
77
LISP
Example 2
Create a new source code file named main.lisp and type the following code in it:
(write (delete-if #'oddp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5) :count 1 :from-end t))
(terpri)
(setq x (vector 'a 'b 'c 'd 'e 'f 'g))
(fill x 'p :start 1 :end 4)
(write x)
When you execute the code, it returns the following result:
(6 8 2 4)
(1 5 7 9 7 3 5)
(1 5 6 7 8 9 2 7 3 5)
#(A P P P E F G)
78
LISP
Example 2
Create a new source code file named main.lisp and type the following code in it:
(write (merge 'vector #(1 3 5) #(2 4 6) #'<))
(terpri)
(write (merge 'list #(1 3 5) #(2 4 6) #'<))
(terpri)
When you execute the code, it returns the following result:
#(1 2 3 4 5 6)
(1 2 3 4 5 6)
Sequence Predicates
The functions every, some, notany, and notevery are called the sequence predicates.
These functions iterate over sequences and test the boolean predicate. All these
functions take a predicate as the first argument and the remaining arguments are
sequences.
Example
Create a new source code file named main.lisp and type the following code in it:
(write (every #'evenp #(2 4 6 8 10)))
(terpri)
(write (some #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (every #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (notany #'evenp #(2 4 6 8 10)))
(terpri)
(write (notevery #'evenp #(2 4 6 8 10 13 14)))
(terpri)
When you execute the code, it returns the following result:
T
T
NIL
79
LISP
NIL
T
Mapping Sequences
The map function allows you to apply a function on to subsequent elements of one or
more sequences.
The map function takes n-arguments function and n sequences and returns a new
sequence after applying the function to subsequent elements of the sequences.
Example
Create a new source code file named main.lisp and type the following code in it:
(write (map 'vector #'* #(2 3 4 5) #(3 5 4 8)))
When you execute the code, it returns the following result:
#(6 15 16 40)
80
19. LISTS
LISP
Lists had been the most important and the primary composite data structure in
traditional LISP. Presently, Common LISP provides other data structures like, vector,
hash table, classes or structures.
Lists are single linked lists. In LISP, lists are constructed as a chain of a simple record
structure named cons linked together.
81
LISP
(terpri)
(write ( cdr (cons 'a (cons 'b (cons 'c nil)))))
When you execute the code, it returns the following result:
(1 . 2)
(A . B)
(1)
(1 2)
(1 2 3)
(A B C)
A
(B C)
The above example shows how you can use cons structures to create a single linked
list. Here, the list (A B C) consists of three cons cells linked together by their cdrs.
Diagrammatically, it could be expressed as:
82
LISP
(terpri)
(write (list 'a 'b 'c))
(terpri)
(write (list 3 4 'a (car '(b . c)) (* 4 -2)))
(terpri)
(write (list (list 'a 'b) (list 'c 'd 'e)))
When you execute the code, it returns the following result:
(1 2)
(A B)
(1 NIL)
(1 2 3)
(A B C)
(3 4 A B -8)
((A B) (C D E))
Example 2
Create a new source code file named main.lisp and type the following code in it:
(defun my-library (title author rating availability)
(list :title title :author author :rating rating :availabilty availability))
(write (getf (my-library "Hunger Game" "Collins" 9 t) :title))
When you execute the code, it returns the following result:
"Hunger Game"
cdr
It takes a list as argument, and returns a list without the first element.
83
LISP
cons
list
It takes two arguments, an element and a list, and returns a list with the
element inserted at the first place.
It takes any number of arguments and returns a list with the arguments
as member elements of the list.
append
last
member
reverse
It takes a list and returns a list with the top elements in reverse order.
84
LISP
A
(B C D E F)
(A B C)
(A (B C) (E F))
(B C E F P Q G)
((E F))
((E F) D C B A)
85
20. SYMBOLS
LISP
In LISP, a symbol is a name that represents data objects and interestingly, the name
itself is a data object.
What makes symbols special is that they have a component called the property
list, or plist.
Property Lists
LISP allows you to assign properties to symbols. For example, let us have a 'person'
object. We would like this 'person' object to have properties like name, gender, height,
weight, address, profession etc. A property is nothing but an attribute name.
A property list is implemented as a list with an even number (possibly zero) of
elements. Each pair of elements in the list constitutes an entry, in which the first item
is the indicator, and the second is the value. When a symbol is created, its property
list is initially empty. Properties are created by using get within a setf form.
For example, the following statements allow us to assign properties title, author,
publisher, and their respective values, to an object (symbol) named 'book'.
Example 1
Create a new source code file named main.lisp and type the following code in it:
((write (setf (get 'books'title) '(Gone with the Wind)))
(terpri)
(write (setf (get 'books 'author) '(Margaret Michel)))
(terpri)
(write (setf (get 'books 'publisher) '(Warner Books)))
When you execute the code, it returns the following result:
(GONE WITH THE WIND)
(MARGARET MICHEL)
(WARNER BOOKS)
Various property list functions allow you to assign properties as well as retrieve, replace
or remove the properties of a symbol.
86
LISP
The get function returns the property list of symbol for a given indicator. It has the
following syntax:
get symbol indicator &optional default
The get function looks for the property list of the given symbol for the specified
indicator. If the symbol is found, then it returns the corresponding value. Otherwise, it
returns specified default value. If default value is not specified, it returns nil.
Example 2
Create a new source code file named main.lisp and type the following code in it:
(setf (get 'books 'title) '(Gone with the Wind))
(setf (get 'books 'author) '(Margaret Micheal))
(setf (get 'books 'publisher) '(Warner Books))
(write (get 'books 'title))
(terpri)
(write (get 'books 'author))
(terpri)
(write (get 'books 'publisher))
When you execute the code, it returns the following result:
(GONE WITH THE WIND)
(MARGARET MICHEAL)
(WARNER BOOKS)
The symbol-plist function allows you to see all the properties of a symbol.
Example 3
Create a new source code file named main.lisp and type the following code in it:
(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)
(terpri)
(write (symbol-plist 'annie))
87
LISP
When you execute the code, it returns the following result:
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)
The remprop function removes the specified property from a symbol.
Example 4
Create a new source code file named main.lisp and type the following code in it:
(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)
(terpri)
(write (symbol-plist 'annie))
(remprop 'annie 'age)
(terpri)
(write (symbol-plist 'annie))
When you execute the code, it returns the following result:
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT)
88
21. VECTORS
LISP
Vectors are one-dimensional arrays, therefore a subtype of array. Vectors and lists are
collectively called sequences. Therefore, all sequence generic functions and array
functions work on vectors too.
Creating Vectors
The vector function allows you to make fixed-size vectors with specific values. It takes
any number of arguments and returns a vector containing those arguments.
Let us see the example:
Example 1
Create a new source code file named main.lisp and type the following code in it:
(setf v1 (vector 1 2 3 4 5))
(setf v2 #(a b c d e))
(setf v3 (vector 'p 'q 'r 's 't))
(write v1)
(terpri)
(write v2)
(terpri)
(write v3)
When you execute the code, it returns the following result:
#(1 2 3 4 5)
#(A B C D E)
#(P Q R S T)
Note that LISP uses the #(...) syntax as the literal notation for vectors. You can use
this #(... ) syntax to create and include literal vectors in your code.
However, these are literal vectors. Hence, modifying them is not defined in LISP.
Therefore,while programming, you should always use the vector function, or the more
general function make-array; to create vectors you plan to modify.
The make-array function is more generic way to create a vector. You can access the
vector elements using the aref function.
89
LISP
Example 2
Create a new source code file named main.lisp and type the following code in it:
(setq a (make-array 5 :initial-element 0))
(setq b (make-array 5 :initial-element 2))
(dotimes (i 5)
(setf (aref a i) i))
(write a)
(terpri)
(write b)
(terpri)
When you execute the code, it returns the following result:
#(0 1 2 3 4)
#(2 2 2 2 2)
90
LISP
(terpri)
(vector-push 'd a)
(vector-push 'e a)
;this will not be entered as the vector limit is 5
(vector-push 'f a)
(write a)
(terpri)
(vector-pop a)
(vector-pop a)
(vector-pop a)
(write a)
When you execute the code, it returns the following result:
#()
#(A B C)
#(A B C D E)
#(A B)
Vectors being sequences, all sequence functions are applicable for vectors. Please refer
the sequences chapter for vector functions.
91
22. SET
LISP
Common LISP does not provide a set data type. However, it provides number of
functions that allow set operations performed on a list.
You can add, remove, and search for items in a list, based on various criteria. You can
also perform various set operations like: union, intersection, and set difference.
92
LISP
(setf *myset* (adjoin 2 *myset*))
;now the original set is changed
(write *myset*)
(terpri)
;adding an existing value
(pushnew 2 *myset*)
;no duplicate allowed
(write *myset*)
(terpri)
;pushing a new value
(pushnew 3 *myset*)
(write *myset*)
(terpri)
When you execute the code, it returns the following result:
NIL
(2 1)
(2 1)
(3 2 1)
Checking Membership
The member group of functions allows you to check whether an element is member
of a set or not.
The following syntaxes are used to check membership:
member item list &key :test :test-not :key
member-if predicate list &key :key
member-if-not predicate list &key :key
These functions search the given list for a given item that satisfies the test. If no such
item is found, then the functions return nil. Otherwise, the tail of the list with the
element as the first element is returned. The search is conducted at the top level only.
These functions can be used as predicates.
Example
93
LISP
Create a new source code file named main.lisp and type the following code in it:
(write (member 'zara '(ayan abdul zara riyan nuha)))
(terpri)
(write (member-if #'evenp '(3 7 2 5/3 'a)))
(terpri)
(write (member-if-not #'numberp '(3 7 2 5/3 'a 'b 'c)))
When you execute the code, it returns the following result:
(ZARA RIYAN NUHA)
(2 5/3 'A)
('A 'B 'C)
Set Union
The union group of functions allows you to perform set union on two lists provided as
arguments to these functions on the basis of a test.
The following syntaxes are used for these functions:
union list1 list2 &key :test :test-not :key
nunion list1 list2 &key :test :test-not :key
The union function takes two lists and returns a new list containing all the elements
present in either of the lists. If there are duplications, then only one copy of the
member is retained in the returned list.
The nunion function performs the same operation but may destroy the argument lists.
Example
Create a new source code file named main.lisp and type the following code in it:
(setq set1 (union '(a b c) '(c d e)))
(setq set2 (union '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch))
94
LISP
(write set2)
(terpri)
(write set3)
When you execute the code, it returns the following result:
(A B C D E)
(#(F H) #(5 6 7) #(A B) #(G H))
(#(A B) #(5 6 7) #(F H) #(5 6 7) #(A B) #(G H))
Note that the union function does not work as expected without :test-not
#'mismatch arguments for a list of three vectors. This is because, the lists are made
of cons cells and although the values look same to us apparently, the cdr part of cells
does not match, so they are not exactly same to LISP interpreter/compiler. This is the
reason for not advising large sets implementation using lists. It works fine for small
sets though.
Set Intersection
The intersection group of functions allows you to perform intersection on two lists
provided as arguments to these functions on the basis of a test.
The following are the syntaxes of these functions:
intersection list1 list2 &key :test :test-not :key
nintersection list1 list2 &key :test :test-not :key
These functions take two lists and return a new list containing all the elements present
in both argument lists. If either list has duplicate entries, the redundant entries may
or may not appear in the result.
Example
Create a new source code file named main.lisp and type the following code in it:
(setq set1 (intersection '(a b c) '(c d e)))
(setq set2 (intersection '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch))
95
LISP
(terpri)
(write set2)
(terpri)
(write set3)
When you execute the code, it returns the following result:
(C)
(#(A B) #(5 6 7))
NIL
The nintersection function is the destructive version of intersection, i.e., it may
destroy the original lists.
Set Difference
The set-difference group of functions allows you to perform set difference on two lists
provided as arguments to these functions on the basis of a test.
The following syntaxes are used for these functions:
set-difference list1 list2 &key :test :test-not :key
nset-difference list1 list2 &key :test :test-not :key
The set-difference function returns a list of elements of the first list that do not appear
in the second list.
Example
Create a new source code file named main.lisp and type the following code in it:
(setq set1 (set-difference '(a b c) '(c d e)))
(setq set2 (set-difference '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch))
(setq set3 (set-difference '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h))))
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)
96
LISP
When you execute the code, it returns the following result:
(A B)
(#(F H))
(#(A B) #(5 6 7) #(F H))
97
23. TREE
LISP
You can build tree data structures from cons cells, as lists of lists. To implement tree
structure, you need to design functionalities that can traverse through the cons cells,
in a specific order. For example, pre-order, in-order, and post-order for binary trees.
Description
It returns a copy of the tree of cons cells x. it recursively copies
both the car and the cdr directions. If x is not a cons cell, the
copy-tree
x
function simply returns x unchanged. If the optional vecp argument
&optional vecp
is true, this function copies vectors (recursively) as well as cons
cells.
98
LISP
It compares two trees of cons cells. If x and y are both cons cells,
tree-equal
&key :test :test- a cons cell, they are compared by eql, or according to the specified
not :key
subst
new
old-new pairs. Each element of the tree (after applying the :key
&key :test :testfunction, if any), is compared with the cars of alist; if it matches,
not :key
it is replaced by the corresponding cdr.
nsublis alist tree
&key :test :test- It works same as sublis, but a destructive version.
not :key
Example 1
Create a new source code file named main.lisp and type the following code in it:
(setq lst (list '(1 2) '(3 4) '(5 6)))
(setq mylst (copy-list lst))
(setq tr (copy-tree lst))
(write lst)
(terpri)
(write mylst)
(terpri)
(write tr)
99
LISP
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
Example 2
Create a new source code file named main.lisp and type the following code in it:
(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(write tr)
(setq trs (subst 7 1 tr))
(terpri)
(write trs)
When you execute the code, it returns the following result:
((1 2 (3 4 5) ((7 8) (7 8 9))))
((7 2 (3 4 5) ((7 8) (7 8 9))))
100
LISP
nil
(cdr (car tree))))
This function returns the next sibling of a given node. It takes a tree node as argument,
and returns a reference to the next sibling node, or nil, if the node does not have any
sibling.
(defun next-sibling (tree)
(cdr tree))
Lastly, we need a function to return the information in a node.
(defun data (tree)
(car (car tree)))
Example
Create a new source code file named main.lisp and type the following code in it:
(defun make-tree (item)
"it creates a new node with item."
(cons (cons item nil) nil))
(defun first-child (tree)
(if (null tree)
nil
(cdr (car tree))))
(defun next-sibling (tree)
(cdr tree))
(defun data (tree)
(car (car tree)))
(defun add-child (tree child)
(setf (car tree) (append (car tree) child))
tree)
101
LISP
(terpri)
(setq newtree (add-child tr mytree))
(terpri)
(write newtree)
When you execute the code, it returns the following result:
10
(2 (3 4 5) ((7 8) (7 8 9)))
102
LISP
The hash table data structure represents a collection of key-and-value pairs that are
organized based on the hash code of the key. It uses the key to access the elements
in the collection.
A hash table is used when you need to access elements by using a key, and you can
identify a useful key value. Each item in the hash table has a key/value pair. The key
is used to access the items in the collection.
The :test argument determines how keys are compared - it should have one of
three values #'eq, #'eql, or #'equal, or one of the three symbols eq, eql, or
equal. If not specified, eql is assumed.
The :size argument sets the initial size of the hash table. This must be an integer
greater than zero.
The :rehash-size argument specifies the amount by which the size of the hash
table can be increased when it becomes full. This can be an integer greater than
zero, which is the number of entries to add, or it can be a floating-point number
103
LISP
greater than 1, which is the ratio of the new size to the old size. The default
value for this argument is implementation-dependent.
The :rehash-threshold argument specifies how full the hash table can get before
it must grow. This must be an integer greater than zero and less than the
:rehash-size ( it is scaled whenever the table is grown), or it can be a floatingpoint number between zero and 1. The default value for this argument is
implementation-dependent.
default: is the value to be returned, if the entry is not found, which is nil, if not
specified.
The gethash function actually returns two values, the second being a predicate value
that is true if an entry was found, and false if no entry was found.
104
LISP
(write (gethash '002 empList))
When you execute the code, it returns the following result:
(CHARLIE BROWN)
(FREDDIE SEAL)
105
LISP
106
LISP
Common LISP provides numerous input-output functions. We have already used the
format function, and print function for output. In this chapter, we will look into some
of the most commonly used input-output functions provided in LISP.
Input Functions
The following table provides the most commonly used input functions of LISP:
Sr.
No.
value recursive-p
It is used in some special situations where it is desirable to determine
precisely which character terminated the extended token.
read-line &optional input-stream eof-error-p eof-value recursive-p
It reads a line of text terminated by a newline.
read-char &optional input-stream eof-error-p eof-value recursive-p
It takes one character from input-stream and returns it as a character object.
unread-char character &optional input-stream
It puts the character most recently read from the input-stream, onto the
front of input-stream.
peek-char &optional peek-type input-stream eof-error-p eof-value
recursive-p
It returns the next character to be read from input-stream, without actually
removing it from the input stream.
107
LISP
listen &optional input-stream
7
10
It takes the characters of the string successively and builds a LISP object
and returns the object. It also returns the index of the first character in the
string not read, or the length of the string (or, length +1), as the case may
be.
parse-integer string &key :start :end :radix :junk-allowed
11
12
It reads one byte from the binary-input-stream and returns it in the form of
an integer.
108
LISP
Assume the user enters 10.2 from the STDIN Input. Then the code returns:
25.2
The read function reads characters from an input stream and interprets them by
parsing as representations of LISP objects.
Example
Create a new source code file named main.lisp and type the following code in it:
; the function AreaOfCircle
; calculates area of a circle
; when the radius is input from keyboard
(defun AreaOfCircle()
(terpri)
(princ "Enter Radius: ")
(setq radius (read))
(setq area (* 3.1416 radius radius))
(princ "Area: ")
(write area))
(AreaOfCircle)
When you execute the code, it returns the following result:
Enter Radius: 5 (STDIN Input)
Area: 78.53999
Example
Create a new source code file named main.lisp and type the following code in it:
(with-input-from-string (stream "Welcome to Tutorials Point!")
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
109
LISP
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (peek-char nil stream nil 'the-end))
(values))
When you execute the code, it returns the following result:
#\W
#\e
#\l
#\c
#\o
#\m
#\e
#\Space
#\t
#\o
#\Space
Output Functions
All output functions in LISP take an optional argument called output-stream, where the
output is sent. If not mentioned or nil, output-stream defaults to the value of the
variable *standard-output*.
The following table provides the most commonly used output functions of LISP:
Sr. No.
110
LISP
prin1object &optional output-stream
print object &optional output-stream
pprint object &optional output-stream
princ object &optional output-stream
All these functions output the printed representation of object to outputstream. However, the following differences are there:
prin1 returns the object as its value.
print prints the object with a preceding newline and followed by a space. It
returns object.
pprint is just like print except that the trailing space is omitted.
princ is just like prin1 except that the output has no escape character
write-to-string object &key :escape :radix :base :circle :pretty :level :length
:case :gensym :array
write-to-stringobject &key :escape :radix :base :circle :pretty :level :length
:case :gensym :array :readably :right-margin :miser-width :lines :pprint-
dispatch
prin1-to-string object
princ-to-string object
The object is effectively printed and the output characters are made into a
string, which is returned.
111
LISP
It outputs a newline to output-stream.
stream has reached its destination, and only then returns nil.
The function force-output initiates the emptying of any internal buffers but
returns nil without waiting for completion or acknowledgment.
The function clear-output attempts to abort any outstanding output
operation in progress in order to allow as little output as possible to continue
to the destination.
10
Example
Create a new source code file named main.lisp and type the following code in it:
; this program inputs a numbers and doubles it
(defun DoubleNumber()
(terpri)
(princ "Enter Number : ")
(setq n1 (read))
(setq doubled (* 2.0 n1))
(princ "The Number: ")
(write n1)
(terpri)
(princ "The Number Doubled: ")
(write doubled)
)
(DoubleNumber)
112
LISP
When you execute the code, it returns the following result:
Enter Number : 3456.78 (STDIN Input)
The Number: 3456.78
The Number Doubled: 6913.56
Formatted Output
The function format is used for producing well formatted text. It has the following
syntax:
format destination control-string &rest arguments
where,
Description
~A
~S
It is followed by S-expressions
~D
~B
~O
~X
~C
~F
113
LISP
~E
~$
~%
~*
~?
Example
Let us rewrite the program for calculating area of circle:
Create a new source code file named main.lisp and type the following code in it:
(defun AreaOfCircle()
(terpri)
(princ "Enter Radius: ")
(setq radius (read))
(setq area (* 3.1416 radius radius))
(format t "Radius: = ~F~% Area = ~F" radius area)
)
(AreaOfCircle)
When you execute the code, it returns the following result:
Enter Radius: 10.234 (STDIN Input)
Radius: = 10.234
Area = 329.03473
114
LISP
We discussed about how standard input and output is handled by common LISP. All
file iput-output functions work for reading from and writing into text and binary files.
Only difference is, the stream we use is not standard input or output, but it is a stream
created for the specific purpose of writing into or reading from files.
In this chapter, we will see how LISP can create, open, close text or binary files for
their data storage.
Opening Files
A file represents a sequence of bytes, be it a text file or binary file.
You can use the open function to create a new file or to open an existing file. It is the
most basic function for opening a file. However, the with-open-file is usually more
convenient and more commonly used.
When a file is opened, a stream object is constructed to represent it in the LISP
environment. All operations on the stream are equivalent to operations on the file.
Syntax for the open function is:
open filename &key :direction :element-type :if-exists :if-does-not-exist
:external-format
where,
The keyword arguments specify the type of stream and error handling ways.
The :direction keyword specifies whether the stream should handle input,
output, or both. It takes the following values:
o
:probe - for checking a existence of a file; the stream is opened and then
closed.
The :element-type specifies the type of the unit of transaction for the stream.
115
LISP
:new-version - it creates a new file with the same name but larger version
number.
:supersede - it supersedes the existing file means, new file is created to replace
old one.
nil - it does not create a file or even a stream just returns nil to indicate failure.
:create - it creates an empty file with the specified name and then uses it.
nil - it does not create a file or even a stream. Instead, it simply returns nil to
indicate failure.
Example
Let us open a file named myfile.txt stored in the /tmp folder as:
(open "/tmp/myfile.txt")
116
LISP
Where,
The options are same as the keyword arguments to the function open.
Example 1
Create a new source code file named main.lisp and type the following code in it:
(with-open-file (stream "/tmp/myfile.txt" :direction :output)
(format stream "Welcome to Tutorials Point!")
(terpri stream)
(format stream "This is a tutorials database")
(terpri stream)
(format stream "Submit your Tutorials, White Papers and Articles into our
Tutorials
Directory."))
Please note that all input-output functions discussed in the previous chapter such as
terpri and format are working for writing into the file we created here.
When you execute the code, it does not return anything. However, the data is written
into the file. The :direction :output keywords allows us do this.
However, we can read from this file using the read-line function.
Example 2
Create a new source code file named main.lisp and type the following code in it:
(let ((in (open "/tmp/myfile.txt" :if-does-not-exist nil)))
(when in
(loop for line = (read-line in nil)
while line do (format t "~a~%" line))
(close in)))
When you execute the code, it returns the following result:
Welcome to Tutorials Point!
This is a tutorials database
Submit your Tutorials, White Papers and Articles into our Tutorials Directory.
117
LISP
Closing a File
If you do not close an open file when you are done with it, every time program will
keep on leaking a new file handle and soon you will discover you are not able to create
new files anymore. Hence, it is important to close a file that you opened as a best
programming practice.
The close function closes a stream.
118
27. STRUCTURES
LISP
Structures are the user-defined data type. They allow you to combine related data
items of different data types. You can access any of the components of a structure.
Structures are used to represent a record. Let us say you need to keep track of your
books in a library. You might want to track the following attributes about each book:
Title
Author
Subject
Book ID
Defining a Structure
The defstruct macro in LISP allows you to define an abstract record structure.
The defstruct statement defines a new data type, with more than one member for
your program.
To discuss the format of the defstruct macro, let us write the definition of the Book
structure. You can define the book structure as:
(defstruct book
title
author
subject
book-id
)
Note:
The above declaration creates a book structure with four named components
namely title, author, subject and book-id. Thus, every object created as type
book will have all these components.
It defines four functions named book-title, book-author, book-subject and bookbook-id, which take one argument, a book structure, and returns the field title,
author, subject and book-id of the book object. These functions are called
the access functions.
119
LISP
The symbol book becomes a data type and you can check it using
the typep predicate.
The #S syntax refers to a structure, and you can use it to read or print instances
of a book.
You can use setf to alter the components of a book as given below:
120
LISP
(setq book3( copy-book book1))
(setf (book-book-id book3) 100)
(terpri)
(write book3)
When you execute the code, it returns the following result:
#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming
Tutorial" :BOOK-ID "478")
#S(BOOK :TITLE "Telecom Billing" :AUTHOR "Zara Ali" :SUBJECT "C-Programming
Tutorial" :BOOK-ID "501")
#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming
Tutorial" :BOOK-ID 100)
121
28. PACKAGES
LISP
122
LISP
rename-package package new-name &optional new-nicknames
It renames a package.
list-all-packages
This function returns a list of all packages that currently exist in the LISP
system.
delete-package package
It deletes a package.
Creating a Package
The defpackage function is used for creating a user defined package. It has the
following syntax:
defpackage :package-name
(:use :common-lisp ...)
(:export :symbol1 :symbol2 ...))
Where,
The :use keyword specifies the packages needed by this package i.e., packages
that define functions used by code in this package.
The :export keyword specifies the symbols that are external in this package.
The make-package function is also used for creating a package. The syntax for this
function is:
make-package package-name &key :nicknames :use
The arguments and keywords has same meaning as explained before.
Using a Package
Once you have created a package, you can use the code in this package, by making it
the current package. The in-package macro makes a package current in the
environment.
123
LISP
Example
Create a new source code file named main.lisp and type the following code in it:
(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello ()
(write-line "Hello! This is Tom's Tutorials Point")
)
(hello)
(in-package dick)
(defun hello ()
(write-line "Hello! This is Dick's Tutorials Point")
)
(hello)
(in-package harry)
(defun hello ()
(write-line "Hello! This is Harry's Tutorials Point")
)
(hello)
(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)
When you execute the code, it returns the following result:
Hello! This is Tom's Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point
124
LISP
Deleting a Package
The delete-package macro allows you to delete a package. The following example
demonstrates this:
Example
Create a new source code file named main.lisp and type the following code in it:
(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello ()
(write-line "Hello! This is Tom's Tutorials Point")
)
(in-package dick)
(defun hello ()
(write-line "Hello! This is Dick's Tutorials Point")
)
(in-package harry)
(defun hello ()
(write-line "Hello! This is Harry's Tutorials Point")
)
(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)
(delete-package tom)
(in-package tom)
(hello)
When you execute the code, it returns the following result:
Hello! This is Tom's Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point
125
LISP
*** - EVAL: variable TOM has no value
126
LISP
This chapter explains Object Oriented condition handling and error handling in LISP.
In Common LISP terminology, exceptions are called conditions. In fact, conditions are
more
general
than
exceptions
in
traditional
programming
languages.
condition represents any occurrence of an event or an error, which might affect various
levels of function call stack. Conditions are capable of altering program flow or halting
program execution. They enforce programmers or users to take decisions. Errors are
a subset of conditions. The errors can be fatal, if they are not managed appropriately.
The condition handling system in LISP has three responsibilities:
1. Signaling a condition
2. Handling the condition
3. Restarting or continuing the program
Signaling a Condition
Signaling a condition means making the user aware of some occurrence of an event
through program execution. A condition can be announced by displaying message on
the screen or by beeping sound. When a condition is signaled, the signaling mechanism
finds the most recently established handler that is compatible with the condition type
and calls its function. Signaling a condition does not affect the program flow.
Handling a Condition
Let us take an example of handling a condition arising out of divide by zero condition.
You need to take the following steps for handling a condition:
Define the condition - "A condition is an object whose class indicates the
general nature of the condition and whose instance data carries information
about the details of the particular circumstances that lead to the condition being
signaled". The define-condition macro is used for defining a condition, which
has the following syntax:
127
LISP
MAKE-CONDITION macro creates new condition objects. It initializes the slots of the
new condition based on :initargs argument.
The following code defines the condition:
(define-condition on-division-by-zero (error)
((message :initarg :message :reader message)))
Writing the Handlers - a condition handler is a code that is used for handling
the signaled condition thereon. It is generally written in one of the higher level
functions that call the erring function. When a condition is signaled, the signaling
mechanism searches for an appropriate handler based on the class of the
condition.
Each handler consists of:
o
The macro handler-case establishes a condition handler. The basic form of a handlercase:
(handler-case expression
error-clause*)
Where, each error clause is of the form:
condition-type ([var]) code)
128
LISP
The basic form of handler-bind is as follows:
(handler-bind (binding*) form*)
Where each binding is a list of the following:
a condition type
The invoke-restart macro finds and invokes the most recently bound restart function
with the specified name as argument. You can have multiple restarts.
Example
In this example, we demonstrate the above concepts by writing a function named
division-function, which creates an error condition if the divisor argument is zero. We
have three anonymous functions that provide three ways to come out of it - by
returning a value 1, by sending a divisor 2 and recalculating, or by returning 1.
Create a new source code file named main.lisp and type the following code in it:
(define-condition on-division-by-zero (error)
((message :initarg :message :reader message)))
(defun handle-infinity ()
(restart-case
(let ((result 0))
(setf result (division-function 10 0))
(format t "Value: ~a~%" result))
(just-continue () nil)))
(return-zero () 0)
(return-value (r) r)
(recalc-using (d) (division-function value1 d))))
129
LISP
(defun high-level-code ()
(handler-bind
((on-division-by-zero
#'(lambda (c)
(format t "error signaled: ~a~%" (message c))
(invoke-restart 'return-zero)))
(handle-infinity))))
(handler-bind
((on-division-by-zero
#'(lambda (c)
(format t "error signaled: ~a~%" (message c))
(invoke-restart 'return-value 1))))
(handle-infinity))
(handler-bind
((on-division-by-zero
#'(lambda (c)
(format t "error signaled: ~a~%" (message c))
(invoke-restart 'recalc-using 2))))
(handle-infinity))
(handler-bind
((on-division-by-zero
#'(lambda (c)
(format t "error signaled: ~a~%" (message c))
(invoke-restart 'just-continue))))
(handle-infinity))
(format t "Done."))
130
LISP
error signaled: denominator is zero
Done.
Apart from the condition system as discussed above, Common LISP also provides
various functions that may be called for signaling an error. Handling of an error, when
signaled, is however, implementation-dependent.
It prints the message and goes directly into the debugger without allowing
any possibility of interception by programmed error-handling facilities.
Example
In this example, the factorial function calculates factorial of a number. However, if the
argument is negative, it raises an error condition.
Create a new source code file named main.lisp and type the following code in it:
131
LISP
(defun factorial (x)
(cond ((or (not (typep x 'integer)) (minusp x))
(error "~S is a negative number." x))
((zerop x) 1)
(t (* x (factorial (- x 1))))))
(write(factorial 5))
(terpri)
(write(factorial -1))
When you execute the code, it returns the following result:
120
*** - -1 is a negative number.
132
LISP
Defining Classes
The defclass macro allows creating user-defined classes. It establishes a class as a
data type. It has the following syntax:
(DEFCLASS class-name (superclass-name*)
(slot-description*)
class-option*)
The slots are variables that store data, or fields.
A slot-description has the form (slot-name slot-option*), where each option is a
keyword followed by a name, expression and other options. Most commonly used slot
options are:
:accessor function-name
:initform expression
:initarg symbol
For example, let us define a Box class, with three slots length, breadth, and height.
(defclass Box ()
(length
breadth
height))
133
LISP
(breadth :accessor breadth)
(height :accessor height)))
You can also specify separate accessor names for reading and writing a slot.
(defclass Box ()
((length :reader get-length :writer set-length)
(breadth :reader get-breadth :writer set-breadth)
(height :reader get-height :writer set-height)))
134
LISP
Height of the Box is 5
; displaying values
135
LISP
Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5
Volume of the Box is 500
Inheritance
LISP allows you to define an object in terms of another object. This is
called inheritance. You can create a derived class by adding features that are new or
different. The derived class inherits the functionalities of the parent class.
The following example explains this:
Example
Create a new source code file named main.lisp and type the following code in it:
(defclass box ()
((length :accessor box-length)
(breadth :accessor box-breadth)
(height :accessor box-height)
(volume :reader volume)))
; method calculating volume
(defmethod volume ((object box))
(* (box-length object) (box-breadth object)(box-height object)))
; displaying values
136
LISP
137