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», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

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

Интервал:

Закладка:

Сделать

This time you'll solve both problems by defining a class, table, to represent individual database tables. Each tableinstance will consist of two slots—one to hold the table's data and another to hold information about the columns in the table that database operations will be able to use. The class looks like this:

(defclass table ()

((rows :accessor rows :initarg :rows :initform (make-rows))

(schema :accessor schema :initarg :schema)))

As in Chapter 3, you can represent the individual rows with plists, but this time around you'll create an abstraction that will make that an implementation detail you can change later without too much trouble. And this time you'll store the rows in a vector rather than a list since certain operations that you'll want to support, such as random access to rows by a numeric index and the ability to sort a table, can be more efficiently implemented with vectors.

The function make-rowsused to initialize the rowsslot can be a simple wrapper around MAKE-ARRAY that builds an empty, adjustable,vector with a fill pointer.

The Package

The package for the code you'll develop in this chapter looks like this:

(defpackage :com.gigamonkeys.mp3-database

(:use :common-lisp

:com.gigamonkeys.pathnames

:com.gigamonkeys.macro-utilities

:com.gigamonkeys.id3v2)

(:export :*default-table-size*

:*mp3-schema*

:*mp3s*

:column

:column-value

:delete-all-rows

:delete-rows

:do-rows

:extract-schema

:in

:insert-row

:load-database

:make-column

:make-schema

:map-rows

:matching

:not-nullable

:nth-row

:random-selection

:schema

:select

:shuffle-table

:sort-rows

:table

:table-size

:with-column-values))

The :usesection gives you access to the functions and macros whose names are exported from the packages defined in Chapter 15, 8, and 25 and the :exportsection exports the API this library will provide, which you'll use in Chapter 29.

(defparameter *default-table-size* 100)

(defun make-rows (&optional (size *default-table-size*))

(make-array size :adjustable t :fill-pointer 0))

To represent a table's schema, you need to define another class, column, each instance of which will contain information about one column in the table: its name, how to compare values in the column for equality and ordering, a default value, and a function that will be used to normalize the column's values when inserting data into the table and when querying the table. The schemaslot will hold a list of columnobjects. The class definition looks like this:

(defclass column ()

((name

:reader name

:initarg :name)

(equality-predicate

:reader equality-predicate

:initarg :equality-predicate)

(comparator

:reader comparator

:initarg :comparator)

(default-value

:reader default-value

:initarg :default-value

:initform nil)

(value-normalizer

:reader value-normalizer

:initarg :value-normalizer

:initform #'(lambda (v column) (declare (ignore column)) v))))

The equality-predicateand comparatorslots of a columnobject hold functions used to compare values from the given column for equivalence and ordering. Thus, a column containing string values might have STRING= as its equality-predicateand STRING< as its comparator, while a column containing numbers might have = and < .

The default-valueand value-normalizerslots are used when inserting rows into the database and, in the case of value-normalizer, when querying the database. When you insert a row into the database, if no value is provided for a particular column, you can use the value stored in the column's default-valueslot. Then the value—defaulted or otherwise—is normalized by passing it and the column object to the function stored in the value-normalizerslot. You pass the column in case the value-normalizerfunction needs to use some data associated with the column object. (You'll see an example of this in the next section.) You should also normalize values passed in queries before comparing them with values in the database.

Thus, the value-normalizer's responsibility is primarily to return a value that can be safely and correctly passed to the equality-predicateand comparatorfunctions. If the value-normalizercan't figure out an appropriate value to return, it can signal an error.

The other reason to normalize values before you store them in the database is to save both memory and CPU cycles. For instance, if you have a column that's going to contain string values but the number of distinct strings that will be stored in the column is small—for instance, the genre column in the MP3 database—you can save space and speed by using the value-normalizerto intern the strings (translate all STRING= values to a single string object). Thus, you'll need only as many strings as there are distinct values, regardless of how many rows are in the table, and you can use EQL to compare column values rather than the slower STRING= . [292] The general theory behind interning objects is that if you're going to compare a particular value many times, it's worth it to pay the cost of interning it. The value-normalizer runs once when you insert a value into the table and, as you'll see, once at the beginning of each query. Since a query can involve invoking the equality-predicate once per row in the table, the amortized cost of interning the values will quickly approach zero.

Defining a Schema

Thus, to make an instance of table, you need to build a list of columnobjects. You could build the list by hand, using LIST and MAKE-INSTANCE . But you'll soon notice that you're frequently making a lot column objects with the same comparator and equality-predicate combinations. This is because the combination of a comparator and equality predicate essentially defines a column type. It'd be nice if there was a way to give those types names that would allow you to say simply that a given column is a string column, rather than having to specify STRING< as its comparator and STRING= as its equality predicate. One way is to define a generic function, make-column, like this:

(defgeneric make-column (name type &optional default-value))

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

Интервал:

Закладка:

Сделать

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

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


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

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

x