Peter Siebel - Practical Common Lisp
Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.
- Название:Practical Common Lisp
- Автор:
- Издательство:Apress
- Жанр:
- Год:2005
- ISBN:1-59059-239-5
- Рейтинг книги:4 / 5. Голосов: 1
-
Избранное:Добавить в избранное
- Отзывы:
-
Ваша оценка:
- 80
- 1
- 2
- 3
- 4
- 5
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-entry
when 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-analyzer
that will invoke the skip-log-entry
restart established in parse-log-file
like 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-entry
like this:
(defun skip-log-entry (c)
(invoke-restart 'skip-log-entry))
Then you could change the definition of log-analyzer
to 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-entry
restart function assumes that a skip-log-entry
restart has been established. If a malformed-log-entry-error
is ever signaled by code called from log-analyzer
without a skip-log-entry
having been established, the call to INVOKE-RESTART
will signal a CONTROL-ERROR
when it fails to find the skip-log-entry
restart. If you want to allow for the possibility that a malformed-log-entry-error
might be signaled from code that doesn't have a skip-log-entry
restart established, you could change the skip-log-entry
function 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-entry
is bound with HANDLER-BIND
, it will handle the condition by invoking the skip-log-entry
restart 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-file
to include a special kind of object representing malformed entries in the list of log-entry
objects; 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-entry
function 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-analyzer
to this (assuming the existence of a malformed-log-entry
class with a :text
initarg):
(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-file
instead 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-entry
restart into parse-log-entry
since that would cause parse-log-entry
to 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-entry
restart on the theory that the condition handler could get the same effect by invoking the use-value
restart with NIL
as the argument; that would require the condition handler to have intimate knowledge of how the parse-log-file
works. As it stands, the skip-log-entry
is 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» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.