Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 1
66-2210-01 Programming in Lisp
Data Abstraction and Mapping
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 2
Data Representation
Record course information– Basic definition
(setf course-1 '(66221001 ; course number (Programming in Lisp) ; course name (Alok Mehta) ; instructor (Computer Science))) ; department
– What is the name of ‘course-1’?> (second course-1)
(Programming in Lisp)– Poor practice - Depends on the ordering of the list– What if order changes, or, you need to add something to the list
(setf course-1 '(66221001 1 ; Credit hours (Programming in Lisp) ; Course name (Alok Mehta) ; Instructor (Computer Science))) ; Department
– All programs that access name of course-1 have to change> (third course-1)
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 3
Association Lists
How do you know ‘1’ represents credit hours? Better way to represent data: Association Lists
(setf course-1 '( (course-number 66221001) (credit-hours 1) (name (Programming in Lisp)) (instructor (Alok Mehta)) (department (Computer Science))))
What is the name of ‘course-1’?> (second (third course-1))
(PROGRAMMING IN LISP)> (assoc 'name course-1)
(NAME (PROGRAMMING IN LISP))> (second (assoc 'name course-1)
(PROGRAMMING IN LISP)
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 4
Simple Database
A database as a list of “records”(setf course-database '( ((course-number 66221001) (credit-hours 1) (name (Programming in Lisp)) (instructor (Alok Mehta)) (department (Computer Science))) ((course-number 66220001) (credit-hours 1) (name (Programming in C++)) (instructor (Louis Ziantz)))))
What is the name?(second (assoc 'name (first course-database)))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 5
Access Functions
Write functions to access low-level details(defun get-course-name (course) (second (assoc 'name course)))
– Don’t have to remember how data is stored– Can change storage details easily– Access to data is achieved at a higher level– Easier to read and understand– More maintainable code
Write functions to construct and manipulate data(defun make-course (&key course-number credit-hours name instructor department) (list (list 'course-number course-number) (list 'credit-hours credit-hours) (list 'name name) (list 'instructor instructor) (list 'department department) ))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 6
Calling Access Functions
> (setf course-1 (make-course :name '(Programming in Java) :instructor ’(Alok Mehta)))
((COURSE-NUMBER NIL) (CREDIT-HOURS NIL) (NAME (PROGRAMMING IN JAVA)) (INSTRUCTOR (ALOK MEHTA)) (DEPARTMENT NIL))
> (get-course-name course-1)(PROGRAMMING IN JAVA)
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 7
A simple database example
(setf courses (list (make-course :course-number '66220001 :name '(Programming in C++) :instructor '(Louis Ziantz)) (make-course :course-number '66221001 :name '(Programming in Lisp) :instructor '(Alok Mehta)) (make-course :course-number '66222001 :name '(Programming in Java) :instructor '(Alok Mehta)) (make-course :course-number '66223001 :name '(Programming in Perl) :instructor '(Louis Ziantz))))
Course Name Instructor Credit Hours Department66220001 Programming in C++ Louis Ziantz66221001 Programming in Lisp Alok Mehta66222001 Programming in Java Alok Mehta66223001 Programming in Perl Louis Ziantz
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 8
Which courses are offered?
Example Usage> (get-course-numbers courses)
(66220001 66221001 66222001 66223001)
(defun get-course-number (course) (second (assoc 'course-number course)))
(defun get-course-numbers (course-list) (if (endp course-list) NIL (cons (get-course-number (first course-
list)) (get-course-numbers (rest course-
list)))))
Implements a “Transformation”SQL Equivalent: SELECT course_number FROM courses;
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 9
Which are taught by Alok?
List the courses taught by Alok Mehta> (get-courses-taught-by-alok courses)
(((COURSE-NUMBER 66221001) …) ((COURSE-NUMBER 66222001) ...) ...)
(defun get-course-instructor (course) (second (assoc 'instructor course)))
(defun taught-by-alok-p (course) (if (equal '(Alok Mehta) (get-course-instructor course)) t NIL))
(defun get-courses-taught-by-alok (course-list) (cond ((endp course-list) NIL) ((taught-by-alok-p (first course-list)) (cons (first course-list) (get-courses-taught-by-alok (rest course-list)))) (t (get-courses-taught-by-alok (rest course-list)))))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 10
How many are taught by Alok
List the courses taught by Alok Mehta [Filter]> (get-courses-taught-by-alok courses)
Implements “Filtering”SQL: SELECT * FROM COURSES WHERE instructor = ‘Alok Mehta’;
How many courses are taught by Alok? [Count]> (length (get-courses-taught-by-alok courses)) 2SQL: SELECT COUNT(*) FROM COURSES WHERE instructor = ‘Alok Mehta’;
What is the first course taught by Alok? [Find]> (first (get-courses-taught-by-alok courses))
((COURSE-NUMBER 66221001) (CREDIT-HOURS NIL) (NAME (PROGRAMMING IN LISP)) (INSTRUCTOR (ALOK MEHTA)) (DEPARTMENT NIL))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 11
More efficient way to Count
A more efficient way to count Don’t have to get all courses first!
(defun count-courses-taught-by-alok (course-list) (cond ((endp course-list) 0) ((taught-by-alok-p (first course-list)) (+ 1 (count-courses-taught-by-alok (rest course-list)))) (t (count-courses-taught-by-alok (rest course-list)))))
A more efficient way to find first course(defun find-first-course-taught-by-alok (course-
list) (cond ((endp course-list) nil) ((taught-by-alok-p (first course-list)) (first course-list)) (t (find-first-course-taught-by-alok (rest course-list)))))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 12
Cliches
Many procedures have a common template(defun <list-transformer> (input-list) (if (endp input-list) nil (cons (<element-transformer> (first input-list)) (<list-transformer> (rest input-list)))))
Example:– List-transformer: get-course-numbers– Element-transformer: get-course-number
(defun get-course-numbers (course-list) (if (endp course-list) NIL (cons (get-course-number (first course-list)) (get-course-numbers (rest course-list)))))
This template is frequently used Lisp has a primitive (MAPCAR) to make this easier
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 13
Mapcar
MAPCAR(mapcar <procedure> <argument>)
Applies <procedure> to each element of <argument>
Example> (mapcar #'oddp '(1 2 3))
(T NIL T)> (mapcar #'get-course-number courses)
(66220001 66221001 66222001 66223001)> (mapcar #'= '(1 2 3) '(3 2 1))
(NIL T NIL)
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 14
Remove-If, Remove-If-Not
Remove-If, Remove-If-Not> (remove-if-not #'taught-by-alok-p courses)
[Removes all courses for which “taught-by-alok-p” returns NIL]
This will return all courses taught by Alok> (remove-if #'taught-by-alok-p courses)
[Removes all courses for which “taught-by-alok-p” returns non-NIL]
This will return all courses NOT taught by Alok
Count-If, Count-If-Not> (count-if #'taught-by-alok-p courses)
Counts the number of elements for which “taught-by-alok-p” returns non-NIL
Find-If, Find-If-Not> (find-if #'taught-by-alok-p courses)
Returns the FIRST element of courses for which “taught-by-alok-p” returns non-NIL
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 15
Funcall
Funcall– Template
(funcall #'<procedure> <arg1> … <argN>)Calls the specified procedure with the given argments
– Equivalent to(<procedure> <arg1> … <argN>)
– Example> (funcall #'+ 3 2 7) ;; Same as (+ 3 2 7)
12– Example 2
> (defun eval-infix (arg1 operator arg2) (funcall operator arg1 arg2))> (eval-infix 3 #'+ 2)
Useful if you need to pass in a procedure name, to be applied at a future time
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 16
Apply
Apply Similar to Funcall (typically) takes two arguments,
– procedure object– list of arguments to be passed to procedure object
(funcall #'+ 3 2 7) ;; Same as (+ 3 2 7)(apply #'+ '(3 2 7)) ;; Same as (+ 3 2 7)
Apply can actually take additional arguments– Extra arguments are combined into a single list– Following are equivalent
(apply #'+ '(1 2 3 4 5 6))(apply #'+ 1 2 3 '(4 5 6))
Argument fed to + is (append (list 1 2 3) ‘(4 5 6))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 17
Lambda Procedures
Useful if you need an “anonymous” procedure Don’t want to give it a name
– A named procedure(defun taught-by-alok-p (course) (if (equal '(Alok Mehta) (get-course-instructor course)) t NIL))
– An equivalent un-named procedure(lambda (course) (if (equal '(Alok Mehta) (get-course-instructor course)) t NIL))
– Example usage: How many courses are taught by Alok?(count-if #'(lambda (course) (if (equal '(Alok Mehta) (get-course-instructor course)) t NIL)) courses)
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 18
Lambda procedures
Advantage Don’t have to make up names for procedures Definition of procedure is close to where it is used
(defun get-courses-taught-by-alok (course-list) (remove-if-not #'(lambda (x) (equal '(Alok Mehta) (get-course-instructor
x))) course-list))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 19
Summary
Use readers, constructors, and writers To hide data details
Transform, Filter, Count, Find are common Can be defined recursively Built-in functions in Lisp make things easier
Mapcar, Remove-If(Not), Count-If(Not), Find-If(Not) Funcall, Apply Lambda
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 20
Iteration
DOTIMES (Review)(dotimes (<counter> <upper-bound> <final-result>) <body>)
– Example(dotimes (i 5) (print i)) ;; prints 0 1 2 3 4
DOLIST(dolist (<element> <list-of-elements> <final-
result>) <body>)
– Example(dolist (elem '(a b c d)) (print elem)) ;; prints
a b c d
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 21
Example of DOLIST
Given a list of ages of people, how many adults?– List of ages
> (setf ages '(3 4 17 21 22 34 2 7))– Adult defined as: >= 21 years old
> (defun adultp (age) (>= age 21))– Using Count-if
(defun count-adult (ages) (count-if #'adultp ages))
– Using dolist(defun count-adult (ages &aux (nadult 0)) (dolist (age ages nadult) (if (adultp age) (setf nadult (+ 1
nadult)))))
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 22
Example (cont.)
Get the ages of the first two adults(defun first-two-adults (ages &aux (nadult 0) (adults nil)) (dolist (age ages) (if (adultp age) (progn (setf nadult (+ nadult 1)) (push age adults) (if (= nadult 2) (return adults))))))
Notes PROGN (and PROG1) are like C/C++ Blocks { … }
> (prog1 (setf a 'x) (setf b 'y) (setf c 'z))X
> (progn (setf a 'x) (setf b 'y) (setf c 'z))Z
RETURN exits the DOLIST block– Note: does not necessarily return from the procedure!– Takes an optional return value
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 23
DO
DO is more general than DOLIST or DOTIMES Example
(defun do-expt (m n) ;; Return M^N (do ((result 1) ;; Bind variable ‘Result’ to 1 (exponent n)) ;; Bind variable ‘Exponent’ to N ((zerop exponent) result) ;; test and return
value (setf result (* m result)) ;; Body (setf exponent (- exponent 1)) ;; Body
Equivalent C/C++ definitionint do_expt (int m, int n) { int result, exponent; for (result=1,exponent=n; (exponent != 0); ) { result = m * result; exponent = exponent - 1; } return result;}
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 24
DO Template
Full DO Template (There is also a DO*)(DO ( (<p1> <i1> <u1>) (<p2> <i2> <u2>) … (<pN> <iN> <uN>) ) ( <term-test> <a1> <a2> … <aN> <result> ) <body> )
Rough equivalent in C/C++for ( <p1>=<i1>, <p2>=<i2>,…,<pN>=<iN>; //Note: Lisp=parallel !(<term-test>); // C/C++ has a “continuation-test” <p1>=<u1>, <p2>=<u2>,…,<pN>=<uN>) { <body>}<a1>; <a2>; … ; <aN>;<result>; // Note: (DO…) in Lisp evaluates to <result>// Note: <p1>,<p2>,…,<pN> are now restored to original values
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping 25
Do-expt, Loop
Here is another (equivalent) definition of do-expt(defun do-expt (m n) (do ((result 1 (* m result)) (exponent n (- exponent 1))) ((zerop exponent) result) ;; Note that there is no body! ))
Loop An infinite loop, terminated only by a (return)
(loop (print '(Say uncle)) (if (equal (read) 'uncle) (return)))
Top Related