NOTE: Unless the homwork specifications specifically outline it, these alternative datatypes are not "legal" even if you do stay within the functional paradigm.
Step 1. load the init_lww.lisp file that you downloaded in Lab 1.
Step 2. You should download the file ~cs2360/public/labs/lab6.lisp at this time, also. After opening it in a editor Buffer, you should not evaluate this file [ As you get to each section evaluate the appropriate functions as needed/directed.] .
Step 3. You should download the two files sherlock.lisp and watson.lisp. You should not open these files until told to do so later in the lab.
Step 4. You should open a new file/buffer. Enter your name and gt-num and save as lab6-results.lisp.
Types are denoted by symbols. So the symbol integer represents a type.
The first takes any object and returns the type of object it is.
? (type-of 12 )
? (type-of 12.0 )
? (type-of 'foo )
? (type-of #'(lambda (x ) (+ x x)) )The second is a predicate for testing type.
? (typep 12 'integer )
? (typep 12 'float )
? (typep 12.0 'float )
? (typep 12 'number )
? (typep 12.0 'number )
? (typep #'(lambda (x) (+ x x )) 'integer)There are situations where you may not always be passed legal input. In these situations there is a macro (it doesn't evaluate its arguments) named check-type that can be useful.
(check-type var-name type-symbol)The above is a simplification of what check-type can do. Essentially, if the var-name isn't of the specified type an error is invoked. An example appears in the lab's associated lisp file. Evaluate that function and try a few of the examples. There is a more robust macro
The next two sections give brief introduction to two new data types. (for more extensive coverage see Steele or a reference book) They are:
To create an array you can use the following routine.
(make-array '( 5 ) :initial-contents '( abc nbc cbs upn wb ))
(make-array '( 4 4 ) :initial-contents '( ( 11 12 13 14 )
( 21 22 23 24 )
( 31 32 33 34 )
( 41 42 43 44 ) ) )
(setf *my-matrix* (make-array '(4 5 ) ) )Although the results of the above might resemble as list. The Listener will print the matrix with the prefix #n(...). Where the n denotes the number of dimensions. A simple vector, a one dimensional array may be entered by prefixing would would be a list by the # , hash,
? #( a 2 3 )
#( a 2 4 )
? (type-of #( a 2 3 ) )
SIMPLE-VECTORThe first argument is the number and size of the dimensions of the array. To retrieve the number of dimensions or the size of a dimension.
(array-rank *my-matrix* )
(array-dimension *my-matrix* 0 )
(array-dimension *my-matrix* 1 )Access to elements of the array are accomplished by the function aref. This function takes a multidimensional array and some subscripts.
? (setf *my-networks* (make-array '( 5 )
:initial-contents '( abc nbc cbs upn wb))
? (aref *my-networks* 0 )
;;??
? (aref *my-networks* 1 )
;;??
? (aref *my-matrix* 0 0 )
;;??Since we're sticking to the functional paradigm for the moment it would be nice to be able to easily transform vectors and matrices back into a nested list. The function coerce can transmute objects of a certain type to other types. Luckily, the maping from
? (coerce #(a b c) 'list )
( A B C )
? (defun mystery-fcn ( vector-of-vectors )
(mapcar #'(lambda (inner-vector )
(coerce inner-vector 'list ))
(coerce vector-of-vectors 'list) ))
?
;;??NOTE: a vector of vectors is different from a 2 dimensional matrix. A 2-D matrix would not be legal input for the above, while #( #( 1 2 3 ) #( 4 5 6 ) #( 7 8 9 ) ) would.
Try accessing out of bounds of an array. To "look before you leap" you
can use the following function:
? (array-in-bounds-p *my-matrix* 1 1 )
? (array-in-bounds-p *my-matrix* 1 10 )Well this should be enough to get you started with arrays. In the file lab6.lisp there is a skeleton of a 8-tile board ADT. You are to implement the prescribed functions using the array datatype. [Hand In] There are examples of the I/O expected of these functions in the associated file directly above where the skeletons lay.
The prototypical structure example is that of a person. Let's say you wanted to use a data-structure to keep track of the attributes of a person (name, email-addr, id-num).
You could use a three element list to keep track of each these. Examples:
(lyman lyman@cc 1005 )
(kurt eiselt@cc 1001 )In this case you could define three selectors to extract the data from the list (e.g. person-name, person-email , and person-id ) and perhaps a constructor to make new "persons".
You could also declare a structure using defstruct to do the same thing.
(defstruct person
name
id )Upon evaluation of the above, the functions make-person and the associated field accessors are automagically created for you. There is some code to try out in lab6.lisp.
Your task to create three new functions outlined below. [Hand In]
person-with-new-name
person-with-new-email
persion-with-new-idIn each case, a copy of the passed structure is returned with new information. Skeletons are provided in lab6.lisp.
What's a namespace? Functions, for instance, are bound to
global symbols. Sometimes it would best if there were multiple globals
environments to avoid the name collisions alluded to above. You should
be very familiar with the concept at the level of functions. For example,
(defun foo ( x ) (bar (* x x )) )
(defun bar ( x ) (+ x 3 ) )In the above both foo and bar have a variable x. However, foo's x is distinct from bar's x. The same is true of packages.
;; In the package FOO
? (defvar x 23 )
;; In the package BAR
? (defvar x 44 )Again the package foo's x is different from the package bar's x. Packages are in some sense a way of composing named global environments.
Unfortunately, the package system is the one thing thing changed significantly from CLtL1 to CLtL2. The below describes the CLtL2 version. The CLtL1 version may be described in a newsgroup post.
When you start your lisp environment your are in the COMMON-LISP-USER
package. In LWW you can tell what package you are in by looking at the
cursor. The short "nickname" for COMMON-LISP-USER is CL-USER which is what
LWW uses as the part of the prompt. Additionally you can type.
? *package*
? (package-nicknames *package* )
? (package-name *package* )The everpresent global variable *package* is always bound to the current package.
The first step in uses packages is to create a new one. In the associated lisp file you will find two package definitions and some other functions. Evaluate these at this time. Next, you may open (File>Open) and evaluate (Buffer>Evaluate ) the files sherlock.lisp and watson.lisp .
You may switch between package by evaluating the following. NOTE: the
case of strings does make a difference. These strings use all capitol
letters.
? (in-pacakge "SHERLOCK" )
? (in-package "WATSON" )
? (in-package "COMMON-LISP-USER" )You should note that after each (in-package .. ) invocation, the cursor should change to the name of the package ( or shortest nickname ) you are now in. Make sure you switch back to the "COMMON-LISP-USER" package before trying the following.
? (describe 'remark-on-piece )
? (describe 'sherlock::remark-on-piece )
? (remark-on-piece *white* )
? (sherlock::remark-on-piece *white* )
? (in-package "WATSON" )
? (echo-piece 'white )
? (echo-piece *white* )
? (in-package "COMMON-LISP-USER")
? (watson::echo-piece 'white )
? (watson::echo-piece *white* )
? (watson::remark-on-piece *black* )
You don't really need to use arrays, vectors, or structures in the homeworks
assignments, but they are useful data types.