LISP Lab manual


LISP
Basic Syntax
LISP programs are made up of three basic building blocks:
  • Atom
  • list
  • string
An atom is a number or string of contiguous characters. It includes numbers and special characters.
Following are examples of some valid atoms:
hello-from-GIMT
name
123008907
*hello*
Block#221
abc123


list is a sequence of atoms and/or other lists enclosed in parentheses. Following are examples of some valid lists:
( i am a list)
(a ( a b c) d e fgh)
(father tom ( susan bill joe))
(sun mon tue wed thur fri sat)
( )


string is a group of characters enclosed in double quotation marks. Following are examples of some valid strings:
" I am a string"
"a ba c d efg #$%^&!"
"Please enter the following details :"
"Hello from GIMT'! "


Adding Comments
The semicolon symbol (;) is used for indicating a comment line.
For example
(write-line "Hello World") ; greet the world
; tell them your whereabouts
(write-line "I am at 'GIMT'! Learning LISP")


When you execute the code, it returns the following result:
Hello World
I am at 'GIMT'! Learning LISP


Naming Conventions in LISP
Name or symbols can consist of any number of alphanumeric characters other than whitespace, open and closing parentheses, double and single quotes, backslash, comma, colon, semicolon and vertical bar. To use these characters in a name, you need to use escape character (\).
A name can have digits but not entirely made of digits, because then it would be read as a number. Similarly a name can have periods, but can't be made entirely of periods.
Use of Single Quotation Mark
LISP evaluates everything including the function arguments and list members.
At times, we need to take atoms or lists literally and don't want them evaluated or treated as function calls.
To do this, we need to precede the atom or the list with a single quotation mark.
The following example demonstrates this:
(write-line "single quote used, it inhibits evaluation")
(write '(* 2 3))
(write-line " ")
(write-line "single quote not used, so expression evaluated")
(write (* 2 3))


When you execute the code, it returns the following result:
single quote used, it inhibits evaluation
(* 2 3)
single quote not used, so expression evaluated
6


Data Types
In LISP, variables are not typed, but data objects are.
LISP data types can be categorized as:
  • Scalar types - for example, number types, characters, symbols etc.
  • Data structures - for example, lists, vectors, bit-vectors, and strings.
Any variable can take any LISP object as its value, unless you have declared 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
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.
Type Specifiers in LISP
array 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 t
cons null simple-array unsigned-byte
double-float number simple-bit-vector vector


Example 1


(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 execute the code, it returns the following result:
10
34.567
123.78
NIL
110000.0
62




Example 2


Next let's check the types of the variables used in the previous example.


(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 execute the code, it returns the following result:
(INTEGER 0 281474976710655)
SINGLE-FLOAT
SINGLE-FLOAT
NULL
SINGLE-FLOAT
(INTEGER 0 281474976710655)


Variables
Global Variables
Global variables have permanent values throughout the LISP system and remain in effect until a new value is specified.
Global variables are generally declared using the defvar construct.
For example:
(defvar x 234)
(write x)
When you execute the code, it returns the following result:
234


Since there is no type declaration for variables in LISP, you directly specify a value for a symbol with the setq construct
For example,
(setq x 10)


Example
setq x 10)
(setq y 20)
(format t "x = ~2d y = ~2d ~%" x y)
(setq x 100)
(setq y 200)
(format t "x = ~2d y = ~2d" x y)
When you execute the code, it returns the following result:
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 lastly the s-expression is evaluated. The value of the last expression evaluated is returned.
If you don't include an initial value for a variable, it is assigned to nil.
Example
(let ((x 'a)
(y 'b)
(z 'c))
(format t "x = ~a y = ~a z = ~a" x y z))


When you execute the code, it returns the following result:
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.
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

(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 execute the code, it returns the following result:
x = (A B C) y = (1 2 3) z = (P Q 10)

Constants

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
(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 execute the code, it returns the following result:
Radius: 10.0
Area: 314.1592




Decision Making
LISP provides following types of decision making constructs.
Construct Description
cond This construct is used for used for checking multiple test-action clauses.It can be compared to the nested if statements in other programming languages.
if The if construct has various forms. In simplest form it is followed by a test clause, a test action and some other consequent action(s). If the test clause evaluates to true, then the test action is executed otherwise, the consequent clause is evaluated.
when In simplest form it is followed by a test clause, and a test action. If the test clause evaluates to true, then the test action is executed otherwise, the consequent clause is evaluated.
case This construct implements multiple test-action clauses like the cond construct. However, it evaluates a key form and allows multiple action clauses based on the evaluation of that key form.


The cond Construct in LISP
Syntax for cond is:


(cond (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 cond, test1, is evaluated to be true, then the related action part, action1, is executed, its value is returned and the rest of the clauses are skipped over.


If test1 evaluates to be nil, then 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


(setq a 10)
(cond ((> a 20)
(format t "~% a is less than 20"))
(t (format t "~% value of a is ~d " a)))
When you execute the code, it returns the following result:
value of a is 10


Please note that the t in the second clause ensures that the last action is performed if none other would.


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
(setq a 10)
(if (> a 20)
(format t "~% a is less than 20"))
(format t "~% value of a is ~d " a)
When you execute the code, it returns the following result:
value of a is 10


Example 2


The if clause can be followed by an optional then clause:


(setq a 10)
(if (> a 20)
then (format t "~% a is less than 20"))
(format t "~% value of a is ~d " a)
When you execute the code, it returns the following result:
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.
(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 execute the code, it returns the following result:
a is greater than 20
value of a is 100


The when Construct


The when macro is followed by a test clause that evaluates to t or nil. If the test clause is evaluated to nil, then no form is evaluated and nil is returned, however it the test result is t, then the action following the test clause is executed.
Syntax for when macro:
(when (test-clause) (<action1) )


Example


(setq a 100)
(when (> a 20)
(format t "~% a is greater than 20"))
(format t "~% value of a is ~d " a)
When you execute the code, it returns the following result:
a is greater than 20
value of a is 100


The case Construct


The case construct implements multiple test-action clauses like the cond construct. However, it evaluates a key form and allows multiple action clauses based on the evaluation of that key form.
The syntax for case macro is:
The template for CASE is:
(case (keyform)
((key1) (action1 action2 ...) )
((key2) (action1 action2 ...) )
...
((keyn) (action1 action2 ...) ))


Example


(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 execute the code, it returns the following result:
Thursday




Loops
LISP provides the following types of constructs to handle looping requirements. Click the following links to check their detail.
Construct Description
loop The loop construct is the simplest form of iteration provided by LISP. In its simplest form It allows you to execute some statement(s) repeatedly until it finds a return statement.
loop for The loop for construct allows you to implement a for-loop like iteration as most common in other languages.
do The do construct is also used for performing iteration using LISP. It provides a structured form of iteration.
dotimes The dotimes construct allows looping for some fixed number of iterations.
dolist The dolist construct allows iteration through each element of a list.


The loop Construct
Example
(setq a 10)
(loop
(setq a (+ a 1))
(write a)
(terpri)
(when (> a 17) (return a)))
When you execute the code, it returns the following result:
11
12
13
14
15
16
17
18


The loop for Construct
The for loop for construct follows several syntax:
(loop for loop-variable in <a list>
do (action))
(loop for loop-variable from value1 to value2
do (action))


Example 1


(loop for x in '(tom dick harry)
do (format t " ~s" x)
)
When you execute the code, it returns the following result:
TOM DICK HARRY


Example 2


(loop for a from 10 to 20
do (print a)
)
When you execute the code, it returns the following result:
10
11
12
13
14
15
16
17
18
19
20


Example 3


(loop for x from 1 to 20
if(evenp x)
do (print x)
)
When you execute the code, it returns the following result:
2
4
6
8
10
12
14
16
18
20




The do Construct
The syntax for do statement:
(do (variable1 value1 updated-value1)
(variable2 value2 updated-value2)
(variable3 value3 updated-value3)
...
(test return-value)
(s-expressions))


After each iteration, the test is evaluated, and if it returns a non-nil or true, the return-value 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


(do ((x 0 (+ 2 x))
(y 20 ( - y 2)))
((= x y)(- x y))
(format t "~% x = ~d y = ~d" x y))
When you execute the code, it returns the following result:
x = 0 y = 20
x = 2 y = 18
x = 4 y = 16
x = 6 y = 14
x = 8 y = 12


The dotimes Construct
Example
(dotimes (n 11)
(print n) (prin1 (* n n)))
When you execute the code, it returns the following result:
0 0
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
10 100


The dolist Construct
Example
(dolist (n '(1 2 3 4 5 6 7 8 9))
(format t "~% Number: ~d Square: ~d" n (* n n)))
When you execute the code, it returns the following result:
Number: 1 Square: 1
Number: 2 Square: 4
Number: 3 Square: 9
Number: 4 Square: 16
Number: 5 Square: 25
Number: 6 Square: 36
Number: 7 Square: 49
Number: 8 Square: 64
Number: 9 Square: 81




Lists
Lists are single linked lists. In LISP, lists are constructed as a chain of a simple record structure named cons linked together.
The cons Record Structure
cons is a record structure containing two components called the car and the cdr.
Cons cells or cons are objects are pairs of values that are created using the function cons.
The cons function takes two arguments and returns a new cons cell containing the two values. These values can be references to any kind of object.
If the second value is not nil, or another cons cell, then the values are printed as a dotted pair enclosed by parentheses.
The two values in a cons cell are called the car and the cdr. The car function is used to access the first value and the cdr function is used to access the second value.
Example
(write (cons 1 2))
(terpri)
(write (cons 'a 'b))
(terpri)
(write (cons 1 nil))
(terpri)
(write (cons 1 (cons 2 nil)))
(terpri)
(write (cons 1 (cons 2 (cons 3 nil))))
(terpri)
(write (cons 'a (cons 'b (cons 'c nil))))
(terpri)
(write ( car (cons 'a (cons 'b (cons 'c nil)))))
(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)


Although cons cells can be used to create lists, however, constructing a list out of nested cons function calls can't be the best solution. The list function is rather used for creating lists in LISP.
The list function can take any number of arguments and as it is a function, it evaluates its arguments.
The first and rest functions give the first element and the rest part of a list. The following examples demonstrate the concepts.
Example 
(write (list 1 2))
(terpri)
(write (list 'a 'b))
(terpri)
(write (list 1 nil))
(terpri)
(write (list 1 2 3))
(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))


List Manipulating Functions


Function Description
car It takes a list as argument, and returns its first element.
cdr It takes a list as argument, and returns a list without the first element.
cons It takes two arguments, an element and a list and returns a list with the element inserted at the first place.
list It takes any number of arguments and returns a list with the arguments as member elements of the list.
append It merges two or more list into one.
last It takes a list and returns a list containing the last element.
member It takes two arguments of which the second must be a list, if the first argument is a member of the second argument, and then it returns the remainder of the list beginning with the first argument.
reverse It takes a list and returns a list with the top elements in reverse order.


Example
(write (car '(a b c d e f)))
(terpri)
(write (cdr '(a b c d e f)))
(terpri)
(write (cons 'a '(b c)))
(terpri)
(write (list 'a '(b c) '(e f)))
(terpri)
(write (append '(b c) '(e f) '(p q) '() '(g)))
(terpri)
(write (last '(a b c d (e f))))
(terpri)
(write (reverse '(a b c d (e f))))


When you execute the code, it returns the following result:
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)




1 comment: