CDs and Records
To keep track of CDs that need to be ripped to MP3s and which CDs should be ripped first, each record in the database will contain the title and artist of the CD, a rating of how much the user likes it, and a flag saying whether it has been ripped. So, to start with, you’ll need a way to represent a single database record (in other words, one CD). Common Lisp gives you lots of choices of data structures from a simple four-item list to a user-defined class, using the Common Lisp Object System (CLOS).
For now you can stay at the simple end of the spectrum and use a list. You can make a list with the **LIST**
function, which, appropriately enough, returns a list of its arguments.
CL-USER> (list 1 2 3)
(1 2 3)
You could use a four-item list, mapping a given position in the list to a given field in the record. However, another flavor of list—called a property list, or plist for short—is even more convenient. A plist is a list where every other element, starting with the first, is a symbol that describes what the next element in the list is. I won’t get into all the details of exactly what a symbol is right now; basically it’s a name. For the symbols that name the fields in the CD database, you can use a particular kind of symbol, called a keyword symbol. A keyword is any name that starts with a colon (:
), for instance, :foo
. Here’s an example of a plist using the keyword symbols :a
, :b
, and :c
as property names:
CL-USER> (list :a 1 :b 2 :c 3)
(:A 1 :B 2 :C 3)
Note that you can create a property list with the same **LIST**
function as you use to create other lists; it’s the contents that make it a plist.
The thing that makes plists a convenient way to represent the records in a database is the function **GETF**
, which takes a plist and a symbol and returns the value in the plist following the symbol, making a plist a sort of poor man’s hash table. Lisp has real hash tables too, but plists are sufficient for your needs here and can more easily be saved to a file, which will come in handy later.
CL-USER> (getf (list :a 1 :b 2 :c 3) :a)
1
CL-USER> (getf (list :a 1 :b 2 :c 3) :c)
3
Given all that, you can easily enough write a function make-cd
that will take the four fields as arguments and return a plist representing that CD.
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
The word **DEFUN**
tells us that this form is defining a new function. The name of the function is make-cd
. After the name comes the parameter list. This function has four parameters: title
, artist
, rating
, and ripped
. Everything after the parameter list is the body of the function. In this case the body is just one form, a call to **LIST**
. When make-cd
is called, the arguments passed to the call will be bound to the variables in the parameter list. For instance, to make a record for the CD Roses by Kathy Mattea, you might call make-cd
like this:
CL-USER> (make-cd "Roses" "Kathy Mattea" 7 t)
(:TITLE "Roses" :ARTIST "Kathy Mattea" :RATING 7 :RIPPED T)