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

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

Интервал:

Закладка:

Сделать

(defclass html-pretty-printer ()

((printer :accessor printer :initarg :printer)

(tab-width :accessor tab-width :initarg :tab-width :initform 2)))

Now you can implement methods specialized on html-pretty-printeron the eight generic functions that make up the backend interface.

The FOO processors use the raw-stringfunction to emit strings that don't need character escaping, either because you actually want to emit normally reserved characters or because all reserved characters have already been escaped. Usually raw-stringis invoked with strings that don't contain newlines, so the default behavior is to use emit/no-newlinesunless the caller specifies a non- NILnewlines-pargument.

(defmethod raw-string ((pp html-pretty-printer) string &optional newlines-p)

(if newlines-p

(emit (printer pp) string)

(emit/no-newlines (printer pp) string)))

The functions newline, freshline, indent, unindent, and toggle-indentingimplement fairly straightforward manipulations of the underlying indenting-printer. The only wrinkle is that the HTML pretty printer generates pretty output only when the dynamic variable *pretty*is true. When it's NIL , you should generate compact HTML with no unnecessary whitespace. So, these methods, with the exception of newline, all check *pretty*before doing anything: [315] Another, more purely object-oriented, approach would be to define two classes, perhaps html-pretty-printer and html-raw-printer , and then define no-op methods specialized on html-raw-printer for the methods that should do stuff only when *pretty* is true. However, in this case, after defining all the no-op methods, you'd end up with more code, and then you'd have the hassle of making sure you created an instance of the right class at the right time. But in general, using polymorphism to replace conditionals is a good strategy.

(defmethod newline ((pp html-pretty-printer))

(emit-newline (printer pp)))

(defmethod freshline ((pp html-pretty-printer))

(when *pretty* (emit-freshline (printer pp))))

(defmethod indent ((pp html-pretty-printer))

(when *pretty*

(incf (indentation (printer pp)) (tab-width pp))))

(defmethod unindent ((pp html-pretty-printer))

(when *pretty*

(decf (indentation (printer pp)) (tab-width pp))))

(defmethod toggle-indenting ((pp html-pretty-printer))

(when *pretty*

(with-slots (indenting-p) (printer pp)

(setf indenting-p (not indenting-p)))))

Finally, the functions embed-valueand embed-codeare used only by the FOO compiler— embed-valueis used to generate code that'll emit the value of a Common Lisp expression, while embed-codeis used to embed a bit of code to be run and its result discarded. In the interpreter, you can't meaningfully evaluate embedded Lisp code, so the methods on these functions always signal an error.

(defmethod embed-value ((pp html-pretty-printer) value)

(error "Can't embed values when interpreting. Value: ~s" value))

(defmethod embed-code ((pp html-pretty-printer) code)

(error "Can't embed code when interpreting. Code: ~s" code))

Using Conditions to Have Your Cake and Eat It Too

An alternate approach would be to use EVAL to evaluate Lisp expressions in the interpreter. The problem with this approach is that EVAL has no access to the lexical environment. Thus, there's no way to make something like this work:

(let ((x 10)) (emit-html '(:p x)))

when xis a lexical variable. The symbol xthat's passed to emit-htmlat runtime has no particular connection to the lexical variable named with the same symbol. The Lisp compiler arranges for references to xin the code to refer to the variable, but after the code is compiled, there's no longer necessarily any association between the name xand that variable. This is the main reason that when you think EVAL is the solution to your problem, you're probably wrong.

However, if xwas a dynamic variable, declared with DEFVAR or DEFPARAMETER (and likely named *x*instead of x), EVAL could get at its value. Thus, it might be useful to allow the FOO interpreter to use EVAL in some situations. But it's a bad idea to always use EVAL . You can get the best of both worlds by combining the idea of using EVAL with the condition system.

First define some error classes that you can signal when embed-valueand embed-codeare called in the interpreter.

(define-condition embedded-lisp-in-interpreter (error)

((form :initarg :form :reader form)))

(define-condition value-in-interpreter (embedded-lisp-in-interpreter) ()

(:report

(lambda (c s)

(format s "Can't embed values when interpreting. Value: ~s" (form c)))))

(define-condition code-in-interpreter (embedded-lisp-in-interpreter) ()

(:report

(lambda (c s)

(format s "Can't embed code when interpreting. Code: ~s" (form c)))))

Now you can implement embed-valueand embed-codeto signal those errors and provide a restart that'll evaluate the form with EVAL .

(defmethod embed-value ((pp html-pretty-printer) value)

(restart-case (error 'value-in-interpreter :form value)

(evaluate ()

:report (lambda (s) (format s "EVAL ~s in null lexical environment." value))

(raw-string pp (escape (princ-to-string (eval value)) *escapes*) t))))

(defmethod embed-code ((pp html-pretty-printer) code)

(restart-case (error 'code-in-interpreter :form code)

(evaluate ()

:report (lambda (s) (format s "EVAL ~s in null lexical environment." code))

(eval code))))

Now you can do something like this:

HTML> (defvar *x* 10)

*X*

HTML> (emit-html '(:p *x*))

and you'll get dropped into the debugger with this message:

Can't embed values when interpreting. Value: *X*

[Condition of type VALUE-IN-INTERPRETER]

Restarts:

0: [EVALUATE] EVAL *X* in null lexical environment.

1: [ABORT] Abort handling SLIME request.

2: [ABORT] Abort entirely from this process.

If you invoke the evaluaterestart, embed-valuewill EVAL*x*, get the value 10, and generate this HTML:

10

Then, as a convenience, you can provide restart functions—functions that invoke the evaluaterestart—in certain situations. The evaluaterestart function unconditionally invokes the restart, while eval-dynamic-variablesand eval-codeinvoke it only if the form in the condition is a dynamic variable or potential code.

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

Интервал:

Закладка:

Сделать

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

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


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

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

x