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

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

Интервал:

Закладка:

Сделать

Making the Dream a Reality

Okay, enough fantasizing about good-looking code; now you need to get to work writing define-binary-class—writing the code that will turn that concise expression of what an ID3 tag looks like into code that can represent one in memory, read one off disk, and write it back out.

To start with, you should define a package for this library. Here's the package file that comes with the version you can download from the book's Web site:

(in-package :cl-user)

(defpackage :com.gigamonkeys.binary-data

(:use :common-lisp :com.gigamonkeys.macro-utilities)

(:export :define-binary-class

:define-tagged-binary-class

:define-binary-type

:read-value

:write-value

:*in-progress-objects*

:parent-of-type

:current-binary-object

:+null+))

The COM.GIGAMONKEYS.MACRO-UTILITIESpackage contains the with-gensymsand once-onlymacros from Chapter 8.

Since you already have a handwritten version of the code you want to generate, it shouldn't be too hard to write such a macro. Just take it in small pieces, starting with a version of define-binary-classthat generates just the DEFCLASS form.

If you look back at the define-binary-classform, you'll see that it takes two arguments, the name id3-tagand a list of slot specifiers, each of which is itself a two-item list. From those pieces you need to build the appropriate DEFCLASS form. Clearly, the biggest difference between the define-binary-classform and a proper DEFCLASS form is in the slot specifiers. A single slot specifier from define-binary-classlooks something like this:

(major-version u1)

But that's not a legal slot specifier for a DEFCLASS . Instead, you need something like this:

(major-version :initarg :major-version :accessor major-version)

Easy enough. First define a simple function to translate a symbol to the corresponding keyword symbol.

(defun as-keyword (sym) (intern (string sym) :keyword))

Now define a function that takes a define-binary-classslot specifier and returns a DEFCLASS slot specifier.

(defun slot->defclass-slot (spec)

(let ((name (first spec)))

`(,name :initarg ,(as-keyword name) :accessor ,name)))

You can test this function at the REPL after switching to your new package with a call to IN-PACKAGE .

BINARY-DATA> (slot->defclass-slot '(major-version u1))

(MAJOR-VERSION :INITARG :MAJOR-VERSION :ACCESSOR MAJOR-VERSION)

Looks good. Now the first version of define-binary-classis trivial.

(defmacro define-binary-class (name slots)

`(defclass ,name ()

,(mapcar #'slot->defclass-slot slots)))

This is simple template-style macro— define-binary-classgenerates a DEFCLASS form by interpolating the name of the class and a list of slot specifiers constructed by applying slot->defclass-slotto each element of the list of slots specifiers from the define-binary-classform.

To see exactly what code this macro generates, you can evaluate this expression at the REPL.

(macroexpand-1 '(define-binary-class id3-tag

((identifier (iso-8859-1-string :length 3))

(major-version u1)

(revision u1)

(flags u1)

(size id3-tag-size)

(frames (id3-frames :tag-size size)))))

The result, slightly reformatted here for better readability, should look familiar since it's exactly the class definition you wrote by hand earlier:

(defclass id3-tag ()

((identifier :initarg :identifier :accessor identifier)

(major-version :initarg :major-version :accessor major-version)

(revision :initarg :revision :accessor revision)

(flags :initarg :flags :accessor flags)

(size :initarg :size :accessor size)

(frames :initarg :frames :accessor frames)))

Reading Binary Objects

Next you need to make define-binary-classalso generate a function that can read an instance of the new class. Looking back at the read-id3-tagfunction you wrote before, this seems a bit trickier, as the read-id3-tagwasn't quite so regular—to read each slot's value, you had to call a different function. Not to mention, the name of the function, read-id3-tag, while derived from the name of the class you're defining, isn't one of the arguments to define-binary-classand thus isn't available to be interpolated into a template the way the class name was.

You could deal with both of those problems by devising and following a naming convention so the macro can figure out the name of the function to call based on the name of the type in the slot specifier. However, this would require define-binary-classto generate the name read-id3-tag, which is possible but a bad idea. Macros that create global definitions should generally use only names passed to them by their callers; macros that generate names under the covers can cause hard-to-predict—and hard-to-debug—name conflicts when the generated names happen to be the same as names used elsewhere. [267] Unfortunately, the language itself doesn't always provide a good model in this respect: the macro DEFSTRUCT , which I don't discuss since it has largely been superseded by DEFCLASS , generates functions with names that it generates based on the name of the structure it's given. DEFSTRUCT 's bad example leads many new macro writers astray.

You can avoid both these inconveniences by noticing that all the functions that read a particular type of value have the same fundamental purpose, to read a value of a specific type from a stream. Speaking colloquially, you might say they're all instances of a single generic operation. And the colloquial use of the word generic should lead you directly to the solution to your problem: instead of defining a bunch of independent functions, all with different names, you can define a single generic function, read-value, with methods specialized to read different types of values.

That is, instead of defining functions read-iso-8859-1-stringand read-u1, you can define read-valueas a generic function taking two required arguments, a type and a stream, and possibly some keyword arguments.

(defgeneric read-value (type stream &key)

(:documentation "Read a value of the given type from the stream."))

By specifying &key without any actual keyword parameters, you allow different methods to define their own &key parameters without requiring them to do so. This does mean every method specialized on read-valuewill have to include either &key or an &rest parameter in its parameter list to be compatible with the generic function.

Then you'll define methods that use EQL specializers to specialize the type argument on the name of the type you want to read.

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

Интервал:

Закладка:

Сделать

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

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


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

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

x