- •Оглавление
- •Предисловие
- •Предисловие к русскому изданию
- •Глава 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. Анализ
- •Комментарии
- •Алфавитный указатель
11.10. Две модели |
199 |
капсуляцией в малом масштабе (стр. 120). Функции stamp и reset ис пользуют общую переменную counter, однако вызывающий код ничего о ней не знает и не может изменить ее напрямую.
В Common Lisp основным методом разделения информации на публич ную и приватную являются пакеты. Чтобы ограничить доступ к чему- либо, мы кладем это в пакет, экспортируя из него лишь имена, являю щиеся частью внешнего интерфейса.
Для инкапсуляции слота достаточно экспортировать лишь функции доступа к нему, но не имя самого слота. Например, мы можем опреде лить класс counter и связать с ним методы increment и clear:
(defpackage "CTR"
(:use "COMMON-LISP")
(:export "COUNTER" "INCREMENT" "CLEAR"))
(in-package ctr)
(defclass counter () ((state :initform 0)))
(defmethod increment ((c counter)) (incf (slot-value c ’state)))
(defmethod clear ((c counter)) (setf (slot-value c ’state) 0))
Функции вне пакета ctr будут иметь возможность создавать экземпля ры counter и вызывать increment и clear, однако не будут иметь доступа к самому слоту и имени state.
А если вы хотите не просто разделить внешний и внутренний интер фейсы класса, но и сделать невозможным сам доступ к значению слота, то можете поступить так: просто отинтернируйте (unintern) имя слота после выполнения кода, который ссылается на него:
(unintern ’state)
Теперь сослаться на слот невозможно ни из какого пакета.°
11.10. Две модели
Объектно-ориентированное программирование может сбить с толку от части из-за того, что есть две модели его реализации: модель передачи сообщений и модель обобщенных функций. Сначала появилась переда ча сообщений, а вторая модель по сути является обобщением первой.
В модели передачи сообщений методы принадлежат объектам и насле дуются так же, как слоты. Чтобы найти площадь объекта, нужно по слать ему сообщение area:
tell obj area
200 |
Глава 11. CLOS |
Это сообщение вызывает соответствующий метод, который obj опреде ляет или наследует.
Иногда нам приходится сообщать дополнительные аргументы. Напри мер, метод move может принимать аргумент, определяющий дальность перемещения. Чтобы переместить obj на 10, пошлем ему следующее со общение:
tell obj move 10
Если записать это другим способом:
(move obj 10)
то становится очевидной ограниченность модели передачи сообщений: мы можем специфицировать лишь первый аргумент. В такой модели не только не получится использовать методы для нескольких объектов, но и трудно даже представить себе такую возможность.
В модели передачи сообщений методы принадлежат объектам, в то время как в модели обобщенных функций методы специализируются для объектов. Если мы будем специализироваться только для первого аргумента, то эти две модели будут по сути одним и тем же. Но в модели обобщенных функций мы можем пойти дальше и специализироваться для любого необходимого количества аргументов. Таким образом, пере дача сообщений – лишь частный случай обобщенных функций, с помо щью которых можно симулировать передачу сообщений, специализи руя методы только по первому аргументу.
Итоги главы
1.В объектно-ориентированном программировании функция f опреде ляется неявно при определении методов f для разных объектов. Объ екты наследуют методы от своих родителей.
2.Определение класса напоминает более многословное определение структуры. Разделяемый слот принадлежит всему классу.
3.Класс наследует слоты своих суперклассов.
4.Предки класса упорядочены в соответствии со списком предшество вания. Алгоритм предшествования легче всего понять визуально.
5.Обобщенная функция состоит из всех методов с тем же именем. Ме тод определяется именем и специализацией своих параметров. Ме тод, используемый при вызове обобщенной функции, определяется согласно порядку предшествования.
6.Первичные методы могут быть дополнены вспомогательными. Стан дартная комбинация методов означает использование around-мето дов, если таковые имеются; в противном случае вызываются снача ла before-, потом первичный, затем after-методы.
7.В операторной комбинации методов все первичные методы рассмат риваются как аргументы заданного оператора.
Упражнения |
201 |
8.Инкапсуляция может быть осуществлена с помощью пакетов.
9.Существуют две модели объектно-ориентированного программиро вания. Модель обобщенных функций является обобщением модели передачи сообщений.
Упражнения
1.Определите параметры accessor, initform, initarg для классов, опре деленных на рис. 11.2. Внесите необходимые правки, чтобы код бо лее не использовал slot-value.
2.Перепишите код на рис. 9.5 так, чтобы сферы и точки были класса ми, а introspect и normal – обобщенными функциями.
3.Имеется набор классов:
(defclass a (c d) ... |
) |
(defclass e () ... |
) |
|||
(defclass b (d c) ... |
) |
(defclass f (h) ... |
) |
|||
(defclass |
c |
() |
...) |
|
(defclass g (h) ... |
) |
(defclass |
d |
(e |
f g) ... |
) |
(defclass h () ... |
) |
(a)Нарисуйте граф, представляющий предков a, и составьте список классов, которым принадлежит экземпляр a в порядке убывания их специфичности.
(b)Повторите аналогичную процедуру для b.
4.Имеются следующие функции:
• precedence: принимает объект и возвращает для него список пред шествования классов по убыванию специфичности.
• methods: принимает обобщенную функцию и возвращает список всех ее методов.
• specializations: принимает метод и возвращает список специали заций его параметров. Каждый элемент возвращаемого списка будет либо классом, либо списком вида (eql x), либо t (для неспе циализированного параметра) .
С помощью перечисленных функций (не пользуясь compute-applicab le-methods или find-method) определите функцию most-spec-app-meth, принимающую обобщенную функцию и список аргументов, с кото рыми она будет вызвана, и возвращающую наиболее специфичный применимый метод, если таковые имеются.
5.Измените код на рис. 11.2 так, чтобы при каждом вызове обобщен ной функции area увеличивался некий глобальный счетчик. Функ ция не должна менять свое поведение никаким иным образом.
6.Приведите пример задачи, трудноразрешимой в том случае, когда лишь первый аргумент обобщенной функции может быть специали зирован.