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», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.
Интервал:
Закладка:
For instance, one way to handle the malformed-log-entry-error
signaled by parse-log-entry
in its caller, parse-log-file
, would be to skip the malformed entry. In the following function, the HANDLER-CASE
expression will either return the value returned by parse-log-entry
or return NIL
if a malformed-log-entry-error
is signaled. (The it
in the LOOP
clause collect it
is another LOOP
keyword, which refers to the value of the most recently evaluated conditional test, in this case the value of entry
.)
(defun parse-log-file (file)
(with-open-file (in file :direction :input)
(loop for text = (read-line in nil nil) while text
for entry = (handler-case (parse-log-entry text)
(malformed-log-entry-error () nil))
when entry collect it)))
When parse-log-entry
returns normally, its value will be assigned to entry
and collected by the LOOP
. But if parse-log-entry
signals a malformed-log-entry-error
, then the error clause will return NIL
, which won't be collected.
JAVA-STYLE EXCEPTON HANDLING
HANDLER-CASE
is the nearest analog in Common Lisp to Java- or Python-style exception handling. Where you might write this in Java:
try {
doStuff();
doMoreStuff();
} catch (SomeException se) {
recover(se);
}
or this in Python:
try:
doStuff()
doMoreStuff()
except SomeException, se:
recover(se)
in Common Lisp you'd write this:
(handler-case
(progn
(do-stuff)
(do-more-stuff))
(some-exception (se) (recover se)))
This version of parse-log-file
has one serious deficiency: it's doing too much. As its name suggests, the job of parse-log-file
is to parse the file and produce a list of log-entry
objects; if it can't, it's not its place to decide what to do instead. What if you want to use parse-log-file
in an application that wants to tell the user that the log file is corrupted or one that wants to recover from malformed entries by fixing them up and re-parsing them? Or maybe an application is fine with skipping them but only until a certain number of corrupted entries have been seen.
You could try to fix this problem by moving the HANDLER-CASE
to a higher-level function. However, then you'd have no way to implement the current policy of skipping individual entries—when the error was signaled, the stack would be unwound all the way to the higher-level function, abandoning the parsing of the log file altogether. What you want is a way to provide the current recovery strategy without requiring that it always be used.
Restarts
The condition system lets you do this by splitting the error handling code into two parts. You place code that actually recovers from errors into restarts , and condition handlers can then handle a condition by invoking an appropriate restart. You can place restart code in mid- or low-level functions, such as parse-log-file
or parse-log-entry
, while moving the condition handlers into the upper levels of the application.
To change parse-log-file
so it establishes a restart instead of a condition handler, you can change the HANDLER-CASE
to a RESTART-CASE
. The form of RESTART-CASE
is quite similar to a HANDLER-CASE
except the names of restarts are just names, not necessarily the names of condition types. In general, a restart name should describe the action the restart takes. In parse-log-file
, you can call the restart skip-log-entry
since that's what it does. The new version will look like this:
(defun parse-log-file (file)
(with-open-file (in file :direction :input)
(loop for text = (read-line in nil nil) while text
for entry = (restart-case (parse-log-entry text)
(skip-log-entry () nil))
when entry collect it)))
If you invoke this version of parse-log-file
on a log file containing corrupted entries, it won't handle the error directly; you'll end up in the debugger. However, there among the various restarts presented by the debugger will be one called skip-log-entry
, which, if you choose it, will cause parse-log-file
to continue on its way as before. To avoid ending up in the debugger, you can establish a condition handler that invokes the skip-log-entry
restart automatically.
The advantage of establishing a restart rather than having parse-log-file
handle the error directly is it makes parse-log-file
usable in more situations. The higher-level code that invokes parse-log-file
doesn't have to invoke the skip-log-entry
restart. It can choose to handle the error at a higher level. Or, as I'll show in the next section, you can add restarts to parse-log-entry
to provide other recovery strategies, and then condition handlers can choose which strategy they want to use.
But before I can talk about that, you need to see how to set up a condition handler that will invoke the skip-log-entry
restart. You can set up the handler anywhere in the chain of calls leading to parse-log-file
. This may be quite high up in your application, not necessarily in parse-log-file
's direct caller. For instance, suppose the main entry point to your application is a function, log-analyzer
, that finds a bunch of logs and analyzes them with the function analyze-log
, which eventually leads to a call to parse-log-file
. Without any error handling, it might look like this:
(defun log-analyzer ()
(dolist (log (find-all-logs))
(analyze-log log)))
The job of analyze-log
is to call, directly or indirectly, parse-log-file
and then do something with the list of log entries returned. An extremely simple version might look like this:
(defun analyze-log (log)
(dolist (entry (parse-log-file log))
(analyze-entry entry)))
where the function analyze-entry
is presumably responsible for extracting whatever information you care about from each log entry and stashing it away somewhere.
Thus, the path from the top-level function, log-analyzer
, to parse-log-entry
, which actually signals an error, is as follows:

Assuming you always want to skip malformed log entries, you could change this function to establish a condition handler that invokes the skip-log-entry
restart for you. However, you can't use HANDLER-CASE
to establish the condition handler because then the stack would be unwound to the function where the HANDLER-CASE
appears. Instead, you need to use the lower-level macro HANDLER-BIND
. The basic form of HANDLER-BIND
is as follows:
Интервал:
Закладка:
Похожие книги на «Practical Common Lisp»
Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.
Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.