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

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

Интервал:

Закладка:

Сделать

(handler-bind ( binding *) form *)

where each binding is a list of a condition type and a handler function of one argument. After the handler bindings, the body of the HANDLER-BIND can contain any number of forms. Unlike the handler code in HANDLER-CASE , the handler code must be a function object, and it must accept a single argument. A more important difference between HANDLER-BIND and HANDLER-CASE is that the handler function bound by HANDLER-BIND will be run without unwinding the stack—the flow of control will still be in the call to parse-log-entrywhen this function is called. The call to INVOKE-RESTART will find and invoke the most recently bound restart with the given name. So you can add a handler to log-analyzerthat will invoke the skip-log-entryrestart established in parse-log-filelike this: [205] The compiler may complain if the parameter is never used. You can silence that warning by adding a declaration (declare (ignore c)) as the first expression in the LAMBDA body.

(defun log-analyzer ()

(handler-bind ((malformed-log-entry-error

#'(lambda (c)

(invoke-restart 'skip-log-entry))))

(dolist (log (find-all-logs))

(analyze-log log))))

In this HANDLER-BIND , the handler function is an anonymous function that invokes the restart skip-log-entry. You could also define a named function that does the same thing and bind it instead. In fact, a common practice when defining a restart is to define a function, with the same name and taking a single argument, the condition, that invokes the eponymous restart. Such functions are called restart functions . You could define a restart function for skip-log-entrylike this:

(defun skip-log-entry (c)

(invoke-restart 'skip-log-entry))

Then you could change the definition of log-analyzerto this:

(defun log-analyzer ()

(handler-bind ((malformed-log-entry-error #'skip-log-entry))

(dolist (log (find-all-logs))

(analyze-log log))))

As written, the skip-log-entryrestart function assumes that a skip-log-entryrestart has been established. If a malformed-log-entry-erroris ever signaled by code called from log-analyzerwithout a skip-log-entryhaving been established, the call to INVOKE-RESTART will signal a CONTROL-ERROR when it fails to find the skip-log-entryrestart. If you want to allow for the possibility that a malformed-log-entry-errormight be signaled from code that doesn't have a skip-log-entryrestart established, you could change the skip-log-entryfunction to this:

(defun skip-log-entry (c)

(let ((restart (find-restart 'skip-log-entry)))

(when restart (invoke-restart restart))))

FIND-RESTART looks for a restart with a given name and returns an object representing the restart if the restart is found and NIL if not. You can invoke the restart by passing the restart object to INVOKE-RESTART . Thus, when skip-log-entryis bound with HANDLER-BIND , it will handle the condition by invoking the skip-log-entryrestart if one is available and otherwise will return normally, giving other condition handlers, bound higher on the stack, a chance to handle the condition.

Providing Multiple Restarts

Since restarts must be explicitly invoked to have any effect, you can define multiple restarts, each providing a different recovery strategy. As I mentioned earlier, not all log-parsing applications will necessarily want to skip malformed entries. Some applications might want parse-log-fileto include a special kind of object representing malformed entries in the list of log-entryobjects; other applications may have some way to repair a malformed entry and may want a way to pass the fixed entry back to parse-log-entry.

To allow more complex recovery protocols, restarts can take arbitrary arguments, which are passed in the call to INVOKE-RESTART . You can provide support for both the recovery strategies I just mentioned by adding two restarts to parse-log-entry, each of which takes a single argument. One simply returns the value it's passed as the return value of parse-log-entry, while the other tries to parse its argument in the place of the original log entry.

(defun parse-log-entry (text)

(if (well-formed-log-entry-p text)

(make-instance 'log-entry ...)

(restart-case (error 'malformed-log-entry-error :text text)

(use-value (value) value)

(reparse-entry (fixed-text) (parse-log-entry fixed-text)))))

The name USE-VALUE is a standard name for this kind of restart. Common Lisp defines a restart function for USE-VALUE similar to the skip-log-entryfunction you just defined. So, if you wanted to change the policy on malformed entries to one that created an instance of malformed-log-entry, you could change log-analyzerto this (assuming the existence of a malformed-log-entryclass with a :textinitarg):

(defun log-analyzer ()

(handler-bind ((malformed-log-entry-error

#'(lambda (c)

(use-value

(make-instance 'malformed-log-entry :text (text c))))))

(dolist (log (find-all-logs))

(analyze-log log))))

You could also have put these new restarts into parse-log-fileinstead of parse-log-entry. However, you generally want to put restarts in the lowest-level code possible. It wouldn't, though, be appropriate to move the skip-log-entryrestart into parse-log-entrysince that would cause parse-log-entryto sometimes return normally with NIL , the very thing you started out trying to avoid. And it'd be an equally bad idea to remove the skip-log-entryrestart on the theory that the condition handler could get the same effect by invoking the use-valuerestart with NIL as the argument; that would require the condition handler to have intimate knowledge of how the parse-log-fileworks. As it stands, the skip-log-entryis a properly abstracted part of the log-parsing API.

Other Uses for Conditions

While conditions are mainly used for error handling, they can be used for other purposes—you can use conditions, condition handlers, and restarts to build a variety of protocols between low- and high-level code. The key to understanding the potential of conditions is to understand that merely signaling a condition has no effect on the flow of control.

The primitive signaling function SIGNAL implements the mechanism of searching for an applicable condition handler and invoking its handler function. The reason a handler can decline to handle a condition by returning normally is because the call to the handler function is just a regular function call—when the handler returns, control passes back to SIGNAL , which then looks for another, less recently bound handler that can handle the condition. If SIGNAL runs out of condition handlers before the condition is handled, it also returns normally.

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

Интервал:

Закладка:

Сделать

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

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


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

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

x