пробелы и убрать все комментарии. Интерпретатор ТЕСО обрабатывал символы последовательно, поэтому приходилось ждать, пока он пройдет очередной комментарий. Вот мы и решили создать примитивный компилятор ТЕСО, который бы сжимал пробелы, убирал комментарии и делал еще кое-что для ускорения работы.

И я поначалу решил разработать уплотнитель макросов на основе идеи Муна. То есть идея была не моя. Я стал думать, как организовать первые несколько функций, взял в качестве примера уже имевшиеся пакеты макросов, сделал своего рода синтез. Тут появился Стеллмен и сказал: “Чем ты занят? Выглядит интересно”. Он подключился к этому делу, и все пошло в десять раз быстрее - Ричард знал ТЕСО досконально.

Выходит, я всерьез работал над реализацией Emacs 4-6 недель, не больше. Потом стало ясно, что Стеллмен все понял в этой программе, и я могу возвращаться к моим магистерским делам. Стеллмен сделал 99,999% всей работы. Но начал ее я.

Сейбел: Сменим тему. Компьютерные науки сегодня тесно связаны с математикой. Насколько важно для программиста-практика вникать, скажем, в математику из Кнута? Или лучше так: “Мне тут нужно отсортировать, пролистаю-ка я Кнута до того места, где он говорит „это наилучший алгоритм', и реализую его”?

Стил: Не знаю... У меня нет математического образования, и мне понятно у Кнута не все, особенно из области высшей или непрерывной математики. Здесь я плаваю. Комбинаторика, перестановки, теория групп - другое дело, все это я часто использую. Это мое рабочее орудие. Не каждому программисту нужна математика, но она упорядочивает понятия, с которыми программисты сталкиваются ежедневно.

Приведу пример из моей недавней работы над параллельными языками в рамках проекта Fortress. Предположим, вам надо сложить сколько-то чисел. Вы можете начать с нуля и прибавлять числа одно за другим - это традиционный последовательный подход.

Заметим, что у операции сложения есть нейтральный элемент. Вы должны начать с нуля. Тривиальное замечание, но все же сделаем его.

А можно сделать по-другому - расположить все числа в ряд и складывать их попарно. Вы получите ряд сумм, и в конце концов останется лишь одна сумма. Если количество чисел нечетное, последнее из них прибавляется к общей сумме и так далее. Этот метод тоже вполне применим. Для чисел с плавающей запятой надо быть строже в расчетах, хотя порой это не требуется - слишком велики издержки.

Результат получится тот же самый, по крайней мере, если мы имеем дело с целыми числами, как если бы мы начинали с нуля и прибавляли числа по одному, - в силу ассоциативности сложения. Иными словами, неважно, каким образом вы группируете числа.

Есть и третий метод. Допустим, имеется сколько-то процессоров. Вы распределяете пары по процессорам. Алгоритм “начать с нуля и прибавлять числа по одному” трудно распараллелить, а вот при методе разбивки на пары у вас как бы образуется дерево, разные части которого обрабатываются разными процессорами. Они делают это независимо друг от друга, и лишь в конце операции должны взаимодействовать между собой, чтобы вы получили сумму.

И это круто. Вот еще одна стратегия распараллеливания, больше похожая на первую: инициализируем какой-нибудь регистр нулем, а потом процессоры борются за то, чтобы взять следующее число и прибавить его к этому регистру. Встает вопрос о синхронизации, но ответ-то будет тот же самый. Ведь сложение не только ассоциативно, но и коммутативно. То есть не имеет значения не только порядок группировки чисел, но и порядок их обработки.

У математиков для описания всего этого есть громоздкие устрашающие слова - “нейтральный элемент”, “ассоциативность”, “коммутативность”. Я попытался растолковать понятнее. Программистам надо просто знать, что порядок операций не имеет значения и что можно перегруппировывать объекты. То есть в какой-то мере математические понятия, я считаю, важны для программистов.

Сейбел: Да, это хороший пример, потому что его поймет каждый, кто знает арифметику. Но не считаете ли вы, что таким же образом в программирование входят и понятия более высокого уровня?

Стил: Предположим, я генерирую отчет. Типичная ситуация: я делаю сколько-то выводов на печать, они должны быть выведены в определенном порядке. В многоядерном мире я, возможно, захочу делать это не в линейном порядке, а разложить на разные процессоры. Как мне связать все воедино? Можно ли использовать те же методы, что при сложении чисел? Выясняется, что здесь есть ассоциативность, но нет коммутативности, - тогда я знаю, какие приемы будут работать для строк, а какие не будут. Как разработчик языков программирования, имеющий дело с созданием параллельных языков, я нахожу эти понятия и прилагающийся к ним словарь очень полезными.

Сейбел: Кстати о создании языков: как менялся ваш подход с течением времени?

Стил: Главную перемену я описал в своем докладе “Growing a Language” (Выращивание языка) на конференции по объектно-ориентированному программированию OOPSLA 1998 года. В 1970-е годы создатель языка готовил для него проект, реализовывал его и на этом всё. Или не всё; но вы оставались с мыслью, что язык завершен.

Возьмем Паскаль. Что-то по каким-то причинам туда вошло, что-то не вошло, но проектирование языка был завершено. Если бы выяснилось, что чего-то не хватает, что работа со строками никуда не годится, что ж, не повезло. Вирт создал такой язык. ПЛ/1 и Ада были спроектированы таким же образом. Возможно, Ада и C++ стали едва ли не последними языками такого рода. В меньшей степени C++ - он все- таки развивался с течением времени.

Затем языки становились все сложнее, было уже невозможно проектировать их за один раз, и эти языки уже эволюционировали с течением времени, потому что они были слишком велики, чтобы их спроектировать или реализовать за один раз. Вот это и определило смену моего подхода к проектированию языков.

Сейбел: Значит, по-вашему, Java проектировался уже по-другому?

Стил: Наверное, нет. Хотя должен был бы. Java менялся благодаря Java Community Process. Это касалось больше API, чем ядра. Последние 12-13 лет к языку добавлялись все новые свойства, но, наверное, его создатели в начале 1990-х думали, что создают совершенный язык для конкретных ограниченных целей. Вы знаете, их целью были ресиверы для телевизоров.

Сейбел: Верно.

Стил: Они не рассчитывали на Интернет или на такую широкую пользовательскую базу, как сейчас. По-моему, они хотели создать компактный, автономный базовый язык, над которым можно было бы надстраивать API для разных целей. Мой доклад “Выращивание языка” отчасти был посвящен этому процессу: тому, как Java оказался слишком маленьким, а пользователям нужно было больше свойств для их целей.

Особенно требовалось нечто вроде итерации с помощью цикла for путем перечисления. И это добавили в язык. Ученые, которые занимались высокопроизводительными научными вычислениями, требовали большей поддержки операций с плавающей запятой и тому подобного. Но участники Java Community Process это в целом отвергли - по причинам не столько техническим, сколько социальным, мне кажется.

Так или иначе, существовала потребность что-то добавлять к языку, и это вылилось в многоплановый социальный процесс. Думаю, для создания действительно успешного языка нужно планировать такой - социальный - процесс в той же мере, в какой и технические особенности языка. Нужно думать о взаимодействии этих двух вещей. Fortress стал нашим - по крайней мере, моим - первым экспериментом подобного рода. И он еще не закончен, мы пока что на середине пути.

Сейбел: A Common Lisp, в создании которого вы участвовали, может служить в этом смысле примером?

Стил: Да, это еще один из “ранних” языков, который, будучи противопоставленным языкам вроде Java, заставил меня задуматься о “выращивании языка”. Я хорошо знаю историю Лиспа, знаю, как возможности его макросов помогли ему безболезненно эволюционировать, помогли людям участвовать в добавлении новых свойств.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату