SYLLABUS Introduction Manipulation of functions in LISP Definition of functions Predicates and conditionals The conditional COND Iteration and recursion Property lists and arrays Mapping functions Lambda functions and internal storage.
Introduction LISP became a common language for artificial intelligence ( AI ) programming, partly owing to the confluence of LISP and AI work at MIT and partly because AI programs capable of “learning” could be written in LISP as self-modifying programs. LISP has evolved through numerous dialects, such as Scheme and Common LISP . 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 effectively. Common Lisp originated, during the 1980s and 1990s, in an attempt to unify the work of several implementation groups that were successors to Maclisp , like ZetaLisp and NIL (New Implementation of Lisp) etc.
Cont …. 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.
Features of Common LISP It is machine-independent It uses iterative design methodology, and easy extensibility. It allows updating the programs dynamically. It provides high level debugging. It provides advanced object-oriented programming. It provides a convenient macro system . It provides wide-ranging data types like, objects, structures, lists, vectors, adjustable arrays, hash-tables, and symbols. It is expression-based.
Cont …. It provides an object-oriented condition system. It provides a complete I/O library. It provides extensive control structures.
Manipulation of functions in LISP The following table provides some commonly used list manipulating functions . Sr.No . Function & Description 1. car It takes a list as argument, and returns its first element. 2. cdr It takes a list as argument, and returns a list without the first element
Cont …. 3. cons It takes two arguments, an element and a list and returns a list with the element inserted at the first place. 4. list It takes any number of arguments and returns a list with the arguments as member elements of the list. 5. append It merges two or more list into one. 6. last It takes a list and returns a list containing the last element .
Cont … 7. 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. 8. reverse It takes a list and returns a list with the top elements in reverse order.
Definition of functions The macro named defun is used for defining functions. The defun macro needs three arguments − Name of the function Parameters of the function Body of the function Syntax for defun is − ( defun name (parameter-list) "Optional documentation string." body)
Example 1 Let's write a function named averagenum that will print the average of four numbers. We will send these numbers as parameters. Create a new source code file named main.lisp and type the following code in it . (defun averagenum (n1 n2 n3 n4) (/ ( + n1 n2 n3 n4) 4) ) (write(averagenum 10 20 30 40 )) When you execute the code, it returns the following result − 25
Predicates and conditionals Sr.No . Predicate & Description 1 atom It takes one argument and returns t if the argument is an atom or nil if otherwise. 2.equal It takes two arguments and returns t if they are structurally equal or nil otherwise. 3.eq It takes two arguments and returns t if they are same identical objects, sharing the same memory location or nil otherwise.
Cont ….. 4.eql It takes two arguments and returns t if the arguments are eq , or if they are numbers of the same type with the same value, or if they are character objects that represent the same character, or nil otherwise. 5.evenp It takes one numeric argument and returns t if the argument is even number or nil if otherwise . 7.zerop It takes one numeric argument and returns t if the argument is zero or nil if otherwise.
Cont … 8.null It takes one argument and returns t if the argument evaluates to nil, otherwise it returns nil . 9.listp It takes one argument and returns t if the argument evaluates to a list otherwise it returns nil. 10.greaterp It takes one or more argument and returns t if either there is a single argument or the arguments are successively larger from left to right, or nil if otherwise.
Cont … 11.lessp It takes one or more argument and returns t if either there is a single argument or the arguments are successively smaller from left to right, or nil if otherwise. 12.numberp It takes one argument and returns t if the argument is a number or nil if otherwise . 13.symbolp It takes one argument and returns t if the argument is a symbol otherwise it returns nil. 14.integerp It takes one argument and returns t if the argument is an integer otherwise it returns nil.
Cont … 15.rationalp It takes one argument and returns t if the argument is rational number, either a ratio or a number, otherwise it returns nil. 16.floatp It takes one argument and returns t if the argument is a floating point number otherwise it returns nil . 17.realp It takes one argument and returns t if the argument is a real number otherwise it returns nil. 18.complexp It takes one argument and returns t if the argument is a complex number otherwise it returns nil.
Cont …. 19..characterp It takes one argument and returns t if the argument is a character otherwise it returns nil. 20.stringp It takes one argument and returns t if the argument is a string object otherwise it returns nil. 21.arrayp It takes one argument and returns t if the argument is an array object otherwise it returns nil . 22.packagep It takes one argument and returns t if the argument is a package otherwise it returns nil.
The conditional COND The cond construct in LISP is most commonly used to permit branching. Syntax for cond is − ( cond (test1 action1) (test2 action2) ... ( testn actionn ))
Cont …. 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 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 greater than 20")) (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 returned is − value of a is 10
Iteration and recursion A program is called recursive when an entity calls itself. A program is call iterative when there is a loop (or repetition). Example: Program to find the factorial of a number // C++ program to find factorial of given number #include<bits/ stdc ++.h> using namespace std ; // ----- Recursion ----- // method to find factorial of given number int factorialUsingRecursion ( int n )
Cont …. { if (n == 0) return 1; // recursion call return n * factorialUsingRecursion (n - 1); } // ----- Iteration ----- // Method to find the factorial of a given number int factorialUsingIteration ( int n)
Cont … { int res = 1, i ; // using iteration for ( i = 2; i <= n; i ++) res *= i ; return res; }
Cont … // Driver method int main() { int num = 5; cout << "Factorial of " << num << " using Recursion is: " << factorialUsingRecursion (5) << endl ;
Cont … cout << "Factorial of " << num << " using Iteration is: " << factorialUsingIteration (5); return 0; }
Property lists and arrays LISP allows you to define single or multiple-dimension arrays using the make-array 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 to the last element. he number of dimensions of an array is called its rank. In LISP, an array element is specified by a sequence of non-negative integer indices. The length of the sequence must equal the rank of the array. Indexing starts from zero. For example, to create an array with 10- cells, named my-array, we can write − ( setf my-array (make-array '(10)))
LISP - Arrays
Cont …. The aref function allows accessing the contents of the cells. It takes two arguments, the name of the array and the index value. For example, to access the content of the tenth cell, we write − ( aref my-array 9)
The Property List Since its inception, Lisp has associated with each symbol a kind of tabular data structure called a property list ( plist for short). A property list contains zero or more entries; each entry associates with a key (called the indicator), which is typically a symbol, an arbitrary Lisp object (called the value or, sometimes, the property). There are no duplications among the indicators; a property list may only have one property at a time with a given name. In this way, given a symbol and an indicator (another symbol), an associated value can be retrieved. A property list is very similar in purpose to an association list. The difference is that a property list is an object with a unique identity; the operations for adding and removing property-list entries are destructive operations that alter the property list rather than making a new one. Association lists, on the other hand, are normally augmented non-destructively (without side effects) by adding new entries to the front (see acons and pairlis ).
Cont …. A property list is implemented as a memory cell containing a list with an even number (possibly zero) of elements. (Usually this memory cell is the property-list cell of a symbol, but any memory cell acceptable to setf can be used if getf and remf are used.) Each pair of elements in the list constitutes an entry; the first item is the indicator, and the second is the value. Because property-list functions are given the symbol and not the list itself, modifications to the property list can be recorded by storing back into the property-list cell of the symbol. When a symbol is created, its property list is initially empty. Properties are created by using get within a setf form. Common Lisp does not use a symbol's property list as extensively as earlier Lisp implementations did. Less-used data, such as compiler, debugging, and documentation information, is kept on property lists in Common Lisp.
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 should be 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 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.
Lambda functions and internal storage 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 −
Cont …. (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
Internal storage "Lisp" is a family of languages, not a single language. Many languages in the family (e.g., Common Lisp) don't specify the internal representations, but rather the contract that the structures and functions have to preserve. In the case of cons, it's roughly the equations: ( car (cons x y)) == x ( cdr (cons x y)) == y and the requirement that cons returns a new object each time it's called. In some Lisps, cons cells are immutable, and so the requirement that a new object is returned isn't present. Of course, there are actually implementations, and they do actually have to store things, and it's not unreasonable to ask how they do that. In general, it's probably best to think of a cons cell as a structure big enough to hold two pointers, and probably some information holding its type (so that it can be recognized as a cons cell). The pointers used by the implementaiton might be tagged, though, so that if, e.g., the first three bits are some special values, the "pointer" can be recognized as the encoding of some primitive value.