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

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

Интервал:

Закладка:

Сделать

For instance, one way to handle the malformed-log-entry-errorsignaled by parse-log-entryin 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-entryor return NIL if a malformed-log-entry-erroris signaled. (The itin the LOOP clause collect itis 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-entryreturns normally, its value will be assigned to entryand collected by the LOOP . But if parse-log-entrysignals 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-filehas one serious deficiency: it's doing too much. As its name suggests, the job of parse-log-fileis to parse the file and produce a list of log-entryobjects; if it can't, it's not its place to decide what to do instead. What if you want to use parse-log-filein 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-fileor parse-log-entry, while moving the condition handlers into the upper levels of the application.

To change parse-log-fileso 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-entrysince 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-fileon 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-fileto continue on its way as before. To avoid ending up in the debugger, you can establish a condition handler that invokes the skip-log-entryrestart automatically.

The advantage of establishing a restart rather than having parse-log-filehandle the error directly is it makes parse-log-fileusable in more situations. The higher-level code that invokes parse-log-filedoesn't have to invoke the skip-log-entryrestart. 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-entryto 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-entryrestart. 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-logis to call, directly or indirectly, parse-log-fileand 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-entryis 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 - фото 11

Assuming you always want to skip malformed log entries, you could change this function to establish a condition handler that invokes the skip-log-entryrestart 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»

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

x