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

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

Интервал:

Закладка:

Сделать

CL-USER> (foo)

Entering foo

Entering BLOCK

Entering bar

Entering baz

Leaving foo

NIL

Note that the only "Leaving . . ." message that prints is the one that appears after the BLOCK in foo.

Because the names of blocks are lexically scoped, a RETURN-FROM always returns from the smallest enclosing BLOCK in the lexical environment where the RETURN-FROM form appears even if the RETURN-FROM is executed in a different dynamic context. For instance, barcould also contain a BLOCK named a, like this:

(defun bar (fn)

(format t " Entering bar~%")

(block a (baz fn))

(format t " Leaving bar~%"))

This extra BLOCK won't change the behavior of fooat all—the name ais resolved lexically, at compile time, not dynamically, so the intervening block has no effect on the RETURN-FROM . Conversely, the name of a BLOCK can be used only by RETURN-FROM s appearing within the lexical scope of the BLOCK ; there's no way for code outside the block to return from the block except by invoking a closure that closes over a RETURN-FROM from the lexical scope of the BLOCK .

TAGBODY and GO work the same way, in this regard, as BLOCK and RETURN-FROM . When you invoke a closure that contains a GO form, if the GO is evaluated, the stack will unwind back to the appropriate TAGBODY and then jump to the specified tag.

BLOCK names and TAGBODY tags, however, differ from lexical variable bindings in one important way. As I discussed in Chapter 6, lexical bindings have indefinite extent, meaning the bindings can stick around even after the binding form has returned. BLOCK s and TAGBODY s, on the other hand, have dynamic extent—you can RETURN-FROM a BLOCK or GO to a TAGBODY tag only while the BLOCK or TAGBODY is on the call stack. In other words, a closure that captures a block name or TAGBODY tag can be passed down the stack to be invoked later, but it can't be returned up the stack. If you invoke a closure that tries to RETURN-FROM a BLOCK , after the BLOCK itself has returned, you'll get an error. Likewise, trying to GO to a TAGBODY that no longer exists will cause an error. [212] This is a pretty reasonable restriction—it's not entirely clear what it'd mean to return from a form that has already returned—unless, of course, you're a Scheme programmer. Scheme supports continuations , a language construct that makes it possible to return from the same function call more than once. But for a variety of reasons, few, if any, languages other than Scheme support this kind of continuation.

It's unlikely you'll need to use BLOCK and TAGBODY yourself for this kind of stack unwinding. But you'll likely be using them indirectly whenever you use the condition system, so understanding how they work should help you understand better what exactly, for instance, invoking a restart is doing. [213] If you're the kind of person who likes to know how things work all the way down to the bits, it may be instructive to think about how you might implement the condition system's macros using BLOCK , TAGBODY , closures, and dynamic variables.

CATCH and THROW are another pair of special operators that can force the stack to unwind. You'll use these operators even less often than the others mentioned so far—they're holdovers from earlier Lisp dialects that didn't have Common Lisp's condition system. They definitely shouldn't be confused with try/ catchand try/ exceptconstructs from languages such as Java and Python.

CATCH and THROW are the dynamic counterparts of BLOCK and RETURN-FROM . That is, you wrap CATCH around a body of code and then use THROW to cause the CATCH form to return immediately with a specified value. The difference is that the association between a CATCH and THROW is established dynamically—instead of a lexically scoped name, the label for a CATCH is an object, called a catch tag , and any THROW evaluated within the dynamic extent of the CATCH that throws that object will unwind the stack back to the CATCH form and cause it to return immediately. Thus, you can write a version of the foo, bar, and bazfunctions from before using CATCH and THROW instead of BLOCK and RETURN-FROM like this:

(defparameter *obj* (cons nil nil)) ; i.e. some arbitrary object

(defun foo ()

(format t "Entering foo~%")

(catch *obj*

(format t " Entering CATCH~%")

(bar)

(format t " Leaving CATCH~%"))

(format t "Leaving foo~%"))

(defun bar ()

(format t " Entering bar~%")

(baz)

(format t " Leaving bar~%"))

(defun baz ()

(format t " Entering baz~%")

(throw *obj* nil)

(format t " Leaving baz~%"))

Notice how it isn't necessary to pass a closure down the stack— bazcan call THROW directly. The result is quite similar to the earlier version.

CL-USER> (foo)

Entering foo

Entering CATCH

Entering bar

Entering baz

Leaving foo

NIL

However, CATCH and THROW are almost too dynamic. In both the CATCH and the THROW , the tag form is evaluated, which means their values are both determined at runtime. Thus, if some code in barreassigned or rebound *obj*, the THROW in bazwouldn't throw to the same CATCH . This makes CATCH and THROW much harder to reason about than BLOCK and RETURN-FROM . The only advantage, which the version of foo, bar, and bazthat use CATCH and THROW demonstrates, is there's no need to pass down a closure in order for low-level code to return from a CATCH —any code that runs within the dynamic extent of a CATCH can cause it to return by throwing the right object.

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

Интервал:

Закладка:

Сделать

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

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


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

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

x