Структура и интерпретация компьютерных программ
Вот я наконец и дочитал эту замечательную книгу. Ну точнее постановил считать её дочитанной, так как предпоследняя глава растянулась чуть ли не на полгода, а последняя обещала и того дольше.
Процесс и правда изрядно затянулся. Я начал её читать ещё в сентябре позапрошлого (2009) года. И вот только пара недель как закончил. Причина очень проста: книга явно требует подходящего настроения и регулярно читать не получалось хронически. Процесс и сам по себе получился не обычным. Я начал её читать с экрана, в виде английской pdf'ки. Однако, когда я был где-то на середине вышел очередной тираж русского издания и я без раздумий добыл себе бумажный экземпляр на русском.
И наверно единственный раз не пожалел, что связался с русским переводом. Надо отдать должное переводчикам - это один из лучших технических переводов, что я видел. И без сомнения наиболее качественный из выпущенного в последние годы. Очень тщательный, последовательный подход к терминологии. Авторы всегда дают оригинальное написание вводя новый термин, но далее в книге используют один и тот же русский вариант. Нет ни диких транслитераций, ни странных оборотов в три слова. Я практически прозрачно переключился с английской версии на русскую.
Ещё важный момент, все примеры в книге выполнены на LISPе (а точнее Scheme). Годика три назад, я наверно по этой причине сделал бы из книжки костер и сплясал бы вокруг него. Однако изучение Smalltalk и Python (а точнее отзывов их авторов о влиянии LISP) в последствии немного сгладили мое отношение к скобочкам. Нельзя не признать, что для первых глав, где демонстрируется куча разных подходов к программированию, он является пожалуй оптимальным выбором. Однако длинные куски кода на LISPе всё-таки страшно выглядят, понимание многих примеров из последних глав отнимало много времени, в основном на вычленение стандартных конструкций из мета-кодировки в скобках.
Итак, о чём же собственно книга.
Первая глава, "Построение абстракций с помощью процедур", рассказывает о базовых техниках функционального программирования. В ней вводятся понятие процедуры, её вычисления, объясняется семантика лямбда-исчисления. Также тут рассматриваются "формы" вычислительных процессов, и то какие потребности в памяти и процессорном времени они порождают. В конце показываются функции высокого порядка и лямбда-выражения, с примерами применения.
Вторая глава, "Построение абстракций с помощью данных", рассказывает о том, что такое данные, как их можно унифицировать (на уровне доступа) с процедурами и почему это бывает важно. Попутно вводится понятие структуры данных и рассматриваются примеры, вроде пар, списков и т.п. Описывается свойство замкнутости для структур данных (программ?), и демонстрируется его важность в дизайне программ. Заканчивается глава по сути кратким введением в ООП, а точнее подробным рассмотрением идеи программирования в "стиле передачи сообщений". Показываются ЛИСПовые техники реализации классов, объектов, методов. Последнее без сомнения лучшее введение в ОО-программирование из всех что я видел. В основном благодаря тому, что мир объектов и сообщений строится вместе с читателем, а не приводится как данность (тут я немного забежал вперёд - достраивается он уже в следующей главе).
Третья глава, "Модульность, объекты и состояние", вводит в стройный мир асбтрактных вычислений, выстроенный в первых главах, проблемы реального мира: присваивание и время. Примерно половина главы посвящена тому как эти явления аккуратно моделировать в языке программирования, и примерно половина конкретным техникам программирования. В этой главе особо порадовал раздел про потоки, который был прочитан с учётом возвратов из следующей главы и перелистываний на досуге раза три. Совершенно замечательный пример простого решения массы сложных проблем, настоятельно рекомендую для прочтения, даже если за всю книгу лень браться.
Четвёртая глава, с жутким названием "Метаязыковая абстракция", посвящена созданию интерпретаторов языков программирования. В ней сначала подробно расписывается архитектура и реализация интерпретатора самой Scheme, а затем вносится в него ряд изменений, для поддержки экзотических методов программирования. Меня, в контексте аспирантуры, конечно больше всего заинтересовал логический интерпретатор (пролог в скобочном синтаксисе), который наверно единственный я более-менее до конца понял.
Ну и на пятую главу, "Вычисления на регистровых машинах", я забил :)
Надо отметить, что книга доставила массу удовольствия в процессе прочтения. Нельзя сказать, что всё написанное там было для меня откровением, но этот материал копился у меня в голове годами, из обрывков статей, блогпостов и собственного печального опыта... В общем стоило ей попасть мне в руки курсе на четвёртом.
Вообще книга заставила много раз подряд проклясть родной универ. Всё-таки способность отечественных преподавателей сделать из даже самых интересных и полезных знаний невнятную, серую, трудноперевариваемую массу просто поражает. Вспомнился и курс функционального программирования, двухмесячный, с быстрым рассмотрением синтаксиса и стандартных функций, какого-то древнего ДОСовского ЛИСПА, увенчанный курсовиком, в котором нужно было сделать базу данных то ли студентов на кафедре, то ли телевизоров на складе. Курс, на котором понятие неизменяемой структуры данных даже не звучало, не говоря уже про то, чтобы объяснить выученному на паскале потоку как с ними работать. И курс объектно-ориентированного программирования, без единого упоминания о передаче сообщений.
Ну да ладно, напоследок, по традиции, критическое замечание к сабжу. В последних главах очень мало диаграмм к сложным примерам кода. Хорошее именование и форматирование это конечно хорошо. Но всё-таки картинки - лучший способ доносить архитектуру до умственно не далёких читателей вроде меня.