130 likes | 285 Views
Additional Lisp Data Types. Arrays and Vectors Hash tables Structures Reference Successful Lisp http://psg.com/~dlamkins/sl/. Arrays and Vectors. Lisp arrays are special types of data objects Array indices start with 0 A 1-dimensional array is also called a vector
E N D
Additional Lisp Data Types • Arrays and Vectors • Hash tables • Structures • Reference Successful Lisp http://psg.com/~dlamkins/sl/
Arrays and Vectors • Lisp arrays are special types of data objects • Array indices start with 0 • A 1-dimensional array is also called a vector • Arrays are created with make-array Array's size is specified at creation > (setf my-vector (make-array '(3))) #(NIL NILNIL) • Elements are accessed and changed using aref > (aref my-vector 2) ; define NIL > (setf (aref my-vector 2)'element-3) ; change ELEMENT-3 > (aref my-vector 2) ; check ELEMENT-3
Array Initialization • Using the :initial-contents keyword > (setf array (make-array 100 :initial-element nil)) #(NIL NILNILNILNILNILNILNILNILNIL ...) > (make-array '(2 3 4) :initialcontents '(((a b c d) (e f g h) (i j k l)) ((m n o p) (q r s t) (u v w x)))) (((A B C D) (E F G H) (I J K L)) ((M N O P) (Q R S T)(U V W X))) • Vector: > (setf *color* (vector 'red 'green 'blue)) #(RED GREEN BLUE) > (aref *color* 1) ; check GREEN > (svref *color* 2) ; check BLUE
Hash Tables • Data structures that store values along with keys • The value is accessed via the key • A hash function allows faster access than searching • Lisp has a built-in hash table data structure • 3 variants based on whether key is matched with eq, eql or equal • Basic operations 1. Access an item given its key (gethash<key> <hashtable>) returns the value referenced by <key> or nil it key not found 2. Insert a new [key, value] entry in the table > (setf (gethash ’george table) ’smith) > (gethash 'george table) SMITH 3. Delete an entry using remhash (remhash<key> <hashtable>)
Hash Table Size Hash Tables are usually implemented as (large) arrays • Hash table with10 items may be stored in an array of 100 elements • Hash tables can be wasteful of memory space • Therefore in CL, hash tables can grow automatically • Specify anoriginalanda growth size when creating hash table (make-hash-table :size <n> :rehash-size <r> :rehashthreshold<t> ) • starts with size <n> • when need increases size in increments of <r> • <t> specifies when size should change • <n>, <r> and <t> have implementation-specific defaults (make-hash-table :size 100 :rehash-size 90 :rehash-threshold :80) when the table has 80 entries, it will grow to190 elements
Successful and Failed Accesses • gethash actually returns two values • the value matching the key & whether the key was found or not (t or nil) • if the key is not in the hash table, both responses are nil but you can provide default return value (gethash<key> <hashtable> <defaultvalue>) (gethash 'key table 'error) returns error if key is not in table • setfreplaces an entry if an entry with the same key exists in the hash table, • no error is indicated • you may want to test whether an entry exists first (if (gethash key table) ’error (setf (gethash key table) value))
Other Hash Table Functions • maphash • applies given function to every entry of the hash table • each entry in the table is a pair (the key and the value), therefore the function must accept two arguments • e.g.: (defun print-hash-items (x y) (print (list x y))) (maphash #’print-hash-items a) -> this prints all entries in the hash table • clrhash • clears all entries from a hash table returns the empty table • hash-table-count • returns the number of entries in the hash table (0 if empty) • implementation of hash tables is not prescribed • e.g., they can be implemented as association lists
Structures • Structures allow you to create non-homogenous data structures • In C, these are called "structs" • Java objects are similar, but not equivalent • Lisp structures offer a lot of short-cuts options and access functions (unlike in C or Java) • Define a structure with (defstruct <name> <slots>) • <slots>are names for each item/member of the structure, e.g. (defstruct person name sex age occupation) • defstruct allows variety of keyword arguments for a slot, e.g. • :type limits a slot to values from a specific data type • :read-only fills a slot's with an initialization/default value (the name and value are wrapped in ())
Generated Functions on Structures • Once a structure is defined with defstruct • You can generate instances of the structure and access the slots • Several functions are automatically generated for you • make-structname creates an instance of structure called structname, e.g.: (make-person) creates an instance of the structure person • You can specify initial values using :slot <value> (make-person :name 'Frank :age 53)returns the structure (setf frank (make-person :name ’Frank :age 53)) stores the instance in the variable frank • Not initialized slots without default values have the value nil • structname-slotname accesses the slot, e.g.: (person-age frank) returns the value of age slot in frank • structname-slotname can be used in setf , e.g.: (setf (person-age frank) 50) • name-p is a type-checking predicate functions • (person-p frank) -> T • you can also write (typep frank 'person)
Other Structure Comments • You can instantiate a structure using #s(<type> <values>) (setf p #s(person :name 'jim :age 44 :sex 'm)) • slots not listed default to their default values or nil • the same form can be used with arrays • You can have other functions generated in defstruct • Define a constructor function • Define a copier function (to make a copy of a structure) • Define a predicate function • one is automatically created, but you can have another name • To create these • wrap the structure name and these commands in ()'s • To define inheritance use:include<struct-type>
Example Structure (defstruct person name (sex 'm) age (occupation 'unknown)) (setf p1 (make-person :name 'Bob :age 20)) (setf p2 (make-person :name 'Sue :sex 'f :age 33 :occupation 'student)) (print (list "enter occupation for" (person-name p1))) (setf (person-occupation p1) (read)) (defstruct (doctor (:include person)) medical-school (done-interning t)) • Note: the structure's name and “parent” are in () then come the new slots (setf p3 (make-doctor :name 'Fred :age 49 :occupation 'doctor :medical-school 'UH)) • similarly define a :print-name function to print out the structure • and define :conc-name to provide another access to a slot • e.g., (p-n p1) instead of (person-name p1) • details are in Successful Lisp, Chapters 3 and 6 • http://www.psg.com/~dlamkins/sl/chapter06.htm
More on Structure “Inheritance” • The inheritance for structures is not controllable - we can’t override what we inherit • In the previous example we had to specify the occupation of p3 to give it an initial value • We would normally prefer to include (occupation ’doctor) in the defstruct for doctor so that all doctors have a default occupation, but that would override part of person’s definition • Similarly, we cannot use multiple inheritance for structures • We can using classes to get around this problem • If a variable points to a structure that inherits from another, you can use either structure to specify the slots • So p1’s slots are accessed by (person-slot p1) but p3’s slots can be accessed either by (person-slot p3) or (doctor-slot p3) • (person-p p1) , (person-p p2) and (doctor-p p2) return t and (doctor-p p1) is nil
Constructor • With :constructor you can specify the name of a default constructor along with its parameters • You can only use this if you place the structure’s name inside () (defstruct (foobar (:constructor construct-foobar (…))) …) not (defstruct foobar (:constructor…)) • The parameters listed should be the same names as the slots • You can use &key or &optional • We change our person: (defstruct (person (:constructor construct-person (name &optional age sex occupation))) name age (sex ’m) (occupation ’unknown)) • Now we can use (make-person) or (make-person:name…) or (construct-person ’fred), etc. • Now we don't need to initialize slots using :slot-name <value> format