- •Оглавление
- •Предисловие
- •Предисловие к русскому изданию
- •Глава 1. Введение
- •1.1. Новые инструменты
- •1.2. Новые приемы
- •1.3. Новый подход
- •Глава 2. Добро пожаловать в Лисп
- •2.1. Форма
- •2.2. Вычисление
- •2.3. Данные
- •2.4. Операции со списками
- •2.5. Истинность
- •2.6. Функции
- •2.7. Рекурсия
- •2.8. Чтение Лиспа
- •2.9. Ввод и вывод
- •2.10. Переменные
- •2.11. Присваивание
- •2.12. Функциональное программирование
- •2.13. Итерация
- •2.14. Функции как объекты
- •2.15. Типы
- •2.16. Заглядывая вперед
- •Итоги главы
- •Упражнения
- •Глава 3. Списки
- •3.1. Ячейки
- •3.2. Равенство
- •3.3. Почему в Лиспе нет указателей
- •3.4. Построение списков
- •3.5. Пример: сжатие
- •3.6. Доступ
- •3.7. Отображающие функции
- •3.8. Деревья
- •3.9. Чтобы понять рекурсию, нужно понять рекурсию
- •3.10. Множества
- •3.11. Последовательности
- •3.12. Стопка
- •3.13. Точечные пары
- •3.14. Ассоциативные списки
- •3.15. Пример: поиск кратчайшего пути
- •3.16. Мусор
- •Итоги главы
- •Упражнения
- •Глава 4. Специализированные структуры данных
- •4.1. Массивы
- •4.2. Пример: бинарный поиск
- •4.3. Строки и знаки
- •4.4. Последовательности
- •4.5. Пример: разбор дат
- •4.6. Структуры
- •4.7. Пример: двоичные деревья поиска
- •4.8. Хеш-таблицы
- •Итоги главы
- •Упражнения
- •Глава 5. Управление
- •5.1. Блоки
- •5.2. Контекст
- •5.3. Условные выражения
- •5.4. Итерации
- •5.5. Множественные значения
- •5.6. Прерывание выполнения
- •5.7. Пример: арифметика над датами
- •Итоги главы
- •Упражнения
- •Глава 6. Функции
- •6.1. Глобальные функции
- •6.2. Локальные функции
- •6.3. Списки параметров
- •6.4. Пример: утилиты
- •6.5. Замыкания
- •6.6. Пример: строители функций
- •6.7. Динамический диапазон
- •6.8. Компиляция
- •6.9. Использование рекурсии
- •Итоги главы
- •Упражнения
- •Глава 7. Ввод и вывод
- •7.1. Потоки
- •7.2. Ввод
- •7.3. Вывод
- •7.4. Пример: замена строк
- •7.5. Макрознаки
- •Итоги главы
- •Упражнения
- •Глава 8. Символы
- •8.1. Имена символов
- •8.2. Списки свойств
- •8.3. А символы-то не маленькие
- •8.4. Создание символов
- •8.5. Использование нескольких пакетов
- •8.6. Ключевые слова
- •8.7. Символы и переменные
- •8.8. Пример: генерация случайного текста
- •Итоги главы
- •Упражнения
- •Глава 9. Числа
- •9.1. Типы
- •9.2. Преобразование и извлечение
- •9.3. Сравнение
- •9.4. Арифметика
- •9.5. Возведение в степень
- •9.6. Тригонометрические функции
- •9.7. Представление
- •9.8. Пример: трассировка лучей
- •Итоги главы
- •Упражнения
- •Глава 10. Макросы
- •10.1. Eval
- •10.2. Макросы
- •10.3. Обратная кавычка
- •10.4. Пример: быстрая сортировка
- •10.5. Проектирование макросов
- •10.6. Обобщенные ссылки
- •10.7. Пример: макросы-утилиты
- •10.8. На Лиспе
- •Итоги главы
- •Упражнения
- •Глава 11. CLOS
- •11.1. Объектно-ориентированное программирование
- •11.2. Классы и экземпляры
- •11.3. Свойства слотов
- •11.4. Суперклассы
- •11.5. Предшествование
- •11.6. Обобщенные функции
- •11.7. Вспомогательные методы
- •11.8. Комбинация методов
- •11.9. Инкапсуляция
- •11.10. Две модели
- •Итоги главы
- •Упражнения
- •Глава 12. Структура
- •12.1. Разделяемая структура
- •12.2. Модификация
- •12.3. Пример: очереди
- •12.4. Деструктивные функции
- •12.5. Пример: двоичные деревья поиска
- •12.6. Пример: двусвязные списки
- •12.7. Циклическая структура
- •12.8. Неизменяемая структура
- •Итоги главы
- •Упражнения
- •Глава 13. Скорость
- •13.1. Правило бутылочного горлышка
- •13.2. Компиляция
- •13.3. Декларации типов
- •13.4. Обходимся без мусора
- •13.5. Пример: заранее выделенные наборы
- •13.6. Быстрые операторы
- •13.7. Две фазы разработки
- •Итоги главы
- •Упражнения
- •Глава 14. Более сложные вопросы
- •14.1. Спецификаторы типов
- •14.2. Бинарные потоки
- •14.3. Макросы чтения
- •14.4. Пакеты
- •14.5. Loop
- •14.6. Особые условия
- •Глава 15. Пример: логический вывод
- •15.1. Цель
- •15.2. Сопоставление
- •15.3. Отвечая на запросы
- •15.4. Анализ
- •Глава 16. Пример: генерация HTML
- •16.1. HTML
- •16.2. Утилиты HTML
- •16.3. Утилита для итерации
- •16.4. Генерация страниц
- •Глава 17. Пример: объекты
- •17.1. Наследование
- •17.2. Множественное наследование
- •17.3. Определение объектов
- •17.4. Функциональный синтаксис
- •17.5. Определение методов
- •17.6. Экземпляры
- •17.7. Новая реализация
- •17.8. Анализ
- •Комментарии
- •Алфавитный указатель
7.5. Макрознаки |
141 |
Чтобы максимально упростить пример, код на рис. 7.2. просто заменя ет одну строку на другую. Однако его несложно обобщить и соорудить поиск по полноценным шаблонам вместо последовательностей букв. Все, что вам потребуется, – заменить вызов char= на функцию проверки на соответствие шаблону.
7.5. Макрознаки
Макрознаки (macro character) – это знаки, имеющие особое значение для функции read. Знаки a и b обычно обрабатываются как есть, однако знак открывающей круглой скобки распознается как начало считыва ния списка.
Макрознаки или их комбинация известны также как макросы чтения (read-macro). Многие макросы чтения в Common Lisp на деле являются сокращениями. Например, кавычка. Цитируемое выражение, напри мер ’a, при обработке с помощью read раскрывается в список (quote a). При наборе подобного выражения в toplevel оно вычисляется сразу же после прочтения, и вы никогда не увидите этого преобразования. Его можно обнаружить, вызывая read явно:
> (car (read-from-string "’a")) QUOTE
Макрос чтения, соответствующий quote, состоит лишь из одного знака, что является редкостью. С ограниченным набором знаков сложно полу чить много односимвольных макросов чтения. Большинство макросов чтения состоит из двух или более знаков.
Такие макросы чтения называются диспетчеризуемыми (dispatching), а их первый знак называется диспетчером. У всех стандартных макро сов чтения знаком-диспетчером является решетка #. С некоторыми из них мы уже знакомы. Например, #’ соответствует (function ...), а ’ яв ляется сокращением для (quote ...).
Следующие диспетчеризуемые макросы чтения мы также уже видели: #(...) является сокращением для векторов, #nА(...) – для массивов, #\ – для знаков, #S(n ...) – для структур. При выводе на печать через prin1 (или format с ~S) такие объекты отобразятся в виде соответствующих макросов чтения.1 Это означает, что объекты, записанные буквально, могут быть считаны обратно в таком же виде:
> (let ((*print-array* t))
(vectorp (read-from-string (format nil "~S" (vector 1 2)))))
T
1Чтобы векторы и массивы печатались таким образом, необходимо устано вить значение *print-array*, равное t.
142 |
Глава 7. Ввод и вывод |
Разумеется, на выходе получается не тот же самый вектор, а другой, но состоящий из тех же элементов.
Не все объекты отображаются в соответствии с таблицей чтения read table. Функции и хеш-таблицы, к примеру, отображаются через #<...>. Фактически #< – тоже макрос чтения, однако при передаче в read он все гда вызывает ошибку. Функции и хеш-таблицы не могут быть напеча таны, а затем прочитаны обратно, и этот макрос чтения гарантирует, что пользователи не будут питать иллюзий на этот счет1.
При определении собственного представления для какого-либо объекта (например, для отображения структур) важно помнить этот принцип. Либо объект в вашем представлении может быть прочитан обратно, ли бо вы используете #<...>.
Итоги главы
1.Потоки – источники ввода и получатели вывода. В потоках знаков ввод и вывод состоят из знаков.
2.Поток, используемый по умолчанию, соответствует toplevel. При от крытии файлов создаются новые потоки.
3.Ввод может обрабатываться как набор объектов, строка знаков или же как отдельные знаки.
4.Функция format предоставляет полное управление выводом.
5.Чтобы осуществить замену строк в текстовом файле, вам придется считывать знаки в буфер.
6.Когда read встречает макрознак типа ’, она вызывает связанную с ним функцию.
Упражнения
1.Определите функцию, возвращающую список из строк, прочитан ных из заданного файла.
2.Определите функцию, возвращающую список выражений, содержа щихся в заданном файле.
3.Пусть в файле некоторого формата комментарии помечаются зна ком %. Содержимое строки от начала знака комментария до ее конца игнорируется. Определите функцию, принимающую два имени фай ла и записывающую во второй содержимое первого с вырезанными комментариями.
1В Лиспе решетка с кавычкой не могут использоваться для описания функ ций, так как этот макрознак не в состоянии представлять замыкание.
Упражнения |
143 |
4. Определите функцию, принимающую двумерный массив чисел
сплавающей запятой и отображающую его в виде аккуратных коло нок. Каждый элемент должен печататься с двумя знаками после за пятой на пространстве 10 знаков. (Исходите из предположения, что все они уместятся в отведенном пространстве.) Вам потребуется функция array-dimensions (стр. 374).
5.Измените функцию stream-subst так, чтобы она понимала шаблоны
сметазнаком +. Если знак + появляется в строке old, он может соот ветствовать любому знаку.
6.Измените функцию stream-subst так, чтобы шаблон мог содержать элемент, соответствующий: любой цифре, любой цифре и букве, лю бому знаку. Шаблон должен уметь распознавать любые читаемые знаки. (Подсказка: old теперь не обязательно должен быть строкой.)