Peter Siebel - Practical Common Lisp

Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Practical Common Lisp: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

CL-USER> (select (artist-selector "Dixie Chicks"))

((:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)

(:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))

Now you just need some more functions to generate selectors. But just as you don't want to have to write select-by-title, select-by-rating, and so on, because they would all be quite similar, you're not going to want to write a bunch of nearly identical selector-function generators, one for each field. Why not write one general-purpose selector-function generator, a function that, depending on what arguments you pass it, will generate a selector function for different fields or maybe even a combination of fields? You can write such a function, but first you need a crash course in a feature called keyword parameters .

In the functions you've written so far, you've specified a simple list of parameters, which are bound to the corresponding arguments in the call to the function. For instance, the following function:

(defun foo (a b c) (list a b c))

has three parameters, a, b, and c, and must be called with three arguments. But sometimes you may want to write a function that can be called with varying numbers of arguments. Keyword parameters are one way to achieve this. A version of foothat uses keyword parameters might look like this:

(defun foo (&key a b c) (list a b c))

The only difference is the &keyat the beginning of the argument list. However, the calls to this new foowill look quite different. These are all legal calls with the result to the right of the ==>:

(foo :a 1 :b 2 :c 3) ==> (1 2 3)

(foo :c 3 :b 2 :a 1) ==> (1 2 3)

(foo :a 1 :c 3) ==> (1 NIL 3)

(foo) ==> (NIL NIL NIL)

As these examples show, the value of the variables a, b, and care bound to the values that follow the corresponding keyword. And if a particular keyword isn't present in the call, the corresponding variable is set to NIL . I'm glossing over a bunch of details of how keyword parameters are specified and how they relate to other kinds of parameters, but you need to know one more detail.

Normally if a function is called with no argument for a particular keyword parameter, the parameter will have the value NIL . However, sometimes you'll want to be able to distinguish between a NIL that was explicitly passed as the argument to a keyword parameter and the default value NIL . To allow this, when you specify a keyword parameter you can replace the simple name with a list consisting of the name of the parameter, a default value, and another parameter name, called a supplied-p parameter. The supplied-p parameter will be set to true or false depending on whether an argument was actually passed for that keyword parameter in a particular call to the function. Here's a version of foothat uses this feature:

(defun foo (&key a (b 20) (c 30 c-p)) (list a b c c-p))

Now the same calls from earlier yield these results:

(foo :a 1 :b 2 :c 3) ==> (1 2 3 T)

(foo :c 3 :b 2 :a 1) ==> (1 2 3 T)

(foo :a 1 :c 3) ==> (1 20 3 T)

(foo) ==> (NIL 20 30 NIL)

The general selector-function generator, which you can call wherefor reasons that will soon become apparent if you're familiar with SQL databases, is a function that takes four keyword parameters corresponding to the fields in our CD records and generates a selector function that selects any CDs that match all the values given to where. For instance, it will let you say things like this:

(select (where :artist "Dixie Chicks"))

or this:

(select (where :rating 10 :ripped nil))

The function looks like this:

(defun where (&key title artist rating (ripped nil ripped-p))

#'(lambda (cd)

(and

(if title (equal (getf cd :title) title) t)

(if artist (equal (getf cd :artist) artist) t)

(if rating (equal (getf cd :rating) rating) t)

(if ripped-p (equal (getf cd :ripped) ripped) t))))

This function returns an anonymous function that returns the logical ANDof one clause per field in our CD records. Each clause checks if the appropriate argument was passed in and then either compares it to the value in the corresponding field in the CD record or returns t, Lisp's version of truth, if the parameter wasn't passed in. Thus, the selector function will return tonly for CDs that match all the arguments passed to where. [30] Note that in Lisp, an IF form, like everything else, is an expression that returns a value. It's actually more like the ternary operator ( ?: ) in Perl, Java, and C in that this is legal in those languages: some_var = some_boolean ? value1 : value2; while this isn't: some_var = if (some_boolean) value1; else value2; because in those languages, if is a statement, not an expression. Note that you need to use a three-item list to specify the keyword parameter rippedbecause you need to know whether the caller actually passed :ripped nil, meaning, "Select CDs whose ripped field is nil," or whether they left out :rippedaltogether, meaning "I don't care what the value of the ripped field is."

Updating Existing Records—Another Use for WHERE

Now that you've got nice generalized selectand wherefunctions, you're in a good position to write the next feature that every database needs—a way to update particular records. In SQL the updatecommand is used to update a set of records matching a particular whereclause. That seems like a good model, especially since you've already got a where-clause generator. In fact, the updatefunction is mostly just the application of a few ideas you've already seen: using a passed-in selector function to choose the records to update and using keyword arguments to specify the values to change. The main new bit is the use of a function MAPCAR that maps over a list, *db*in this case, and returns a new list containing the results of calling a function on each item in the original list.

(defun update (selector-fn &key title artist rating (ripped nil ripped-p))

(setf *db*

(mapcar

#'(lambda (row)

(when (funcall selector-fn row)

(if title (setf (getf row :title) title))

(if artist (setf (getf row :artist) artist))

(if rating (setf (getf row :rating) rating))

(if ripped-p (setf (getf row :ripped) ripped)))

row) *db*)))

One other new bit here is the use of SETF on a complex form such as (getf row :title). I'll discuss SETF in greater detail in Chapter 6, but for now you just need to know that it's a general assignment operator that can be used to assign lots of "places" other than just variables. (It's a coincidence that SETF and GETF have such similar names—they don't have any special relationship.) For now it's enough to know that after (setf (getf row :title) title), the plist referenced by row will have the value of the variable titlefollowing the property name :title. With this updatefunction if you decide that you really dig the Dixie Chicks and that all their albums should go to 11, you can evaluate the following form:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Practical Common Lisp»

Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Practical Common Lisp»

Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x