действительности на Прологе, на Фортране и на Erlang даже очень много. Чуть-чуть на Ruby и на Haskell. Я знаком со всеми языками, но не на всех могу программировать. Хотя я могу писать программы на довольно многих языках.
Сейбел: Но не на C++?
Армстронг: Нет. На C++ я едва могу читать и писать. Не люблю C++; плохо его чувствую, он слишком переусложнен. Мне по душе компактные небольшие языки, а этот большой и громоздкий.
Сейбел: Какие языки повлияли на структуру Erlang?
Армстронг: Пролог. Разумеется, он вырос из Пролога.
Сейбел: Сегодня в нем уже непросто распознать то, что идет от Пролога.
Армстронг: Унификация, сопоставление образцов - все это напрямую идет от Пролога. Как и структуры данных. Синтаксис кортежей и списков слегка различается, но тем не менее очень похож. Еще теория взаимодействующих последовательных процессов Тони Хоара. Я также читал об охраняемых командах Дейкстры. Вот почему я требую, чтобы сопоставление с образцом всегда было явным, не должно быть случая по умолчанию, всегда должна быть ветка с совпадением. Вот основные влияния.
Сейбел: А функциональный облик языка - он откуда?
Армстронг: После внедрения параллелизма в Пролог надо было сделать так, чтобы после какого-нибудь действия не происходил возврат назад. В Прологе можно вызвать что-нибудь и вернуться назад, полностью уничтожая эффект от вызова. Поэтому идея была та, чтобы после команды, скажем “Пуск ракет”, они вылетают - ррраз! - и отменить уже нельзя. Чистые Пролог-программы обратимы. Но при взаимодействии с реальным миром все действия совершаются только в одном направлении. Подали команду “Пуск” - ракеты пущены. Подали команду “Зеленый сигнал светофора” - загорается зеленый, и нельзя потом пересмотреть решение, сочтя его плохим.
Итак, у нас есть язык с поддержкой параллельных процессов, и уже внутри них мы имеем самый настоящий Пролог с возвратами и всем прочим. Пролог, в котором там и сям сделаны срезы, чтобы избежать возврата, стал весьма детерминированным.
Сейбел: Где необратимые программы могут посылать сообщения другим процессам?
Армстронг: Да. Но это просто вызов функции, хотя, возможно, и не функции, запускающей ракеты. Это вызов функции, которая вызывает другую, а та - функцию, запускающую ракеты. По этой причине код, который вы создаете, становится все более функциональным, превращаясь в диалект Пролога - функциональное подмножество. А функциональное подмножество можно сделать полноценным функциональным языком.
Сейбел: Erlang сильно отличается от прочих функциональных языков, поскольку в нем есть динамическая типизация. Вы ощущаете свою принадлежность к сообществу функциональных программистов?
Армстронг: Безусловно. На конференциях по функциональному программированию мы спорим, выпячивая расхождения. Мы спорим о “жадных” и “ленивых” вычислениях, о динамической и статической типизации. Но несмотря ни на что, остается центральная идея функционального программирования:
Было бы здорово, если бы Erlang пользовался преимуществами статической типизации. Возможно, в отдельных местах мы сумеем аннотировать программы так, чтобы типы стали более явными, тогда компилятор сможет порождать типы и генерировать более качественный код.
Сторонники статической типизации говорят: “Мы оцениваем сполна плюсы динамического подхода при маршалинге структур данных”. Мы не можем послать любую программу по проводу и воссоздать ее на другом конце - нам нужно знать тип. И вот мы имеем то, что Карделли назвал перманентно неконсистентной системой. Система, которая постоянно растет и меняется, при этом ее части могут быть временно неконсистентными. Если я меняю код, он не ведет себя как неделимый объект. Часть узлов меняются, остальные нет. Они общаются друг с другом - ведь в какие-то периоды времени они консистентны. А когда мы переходим через коммуникационную границу, как определить, что она проведена правильно? Тут надо кое-что проверять.
Сейбел: Когда-то вы отлаживали чужие программы за пиво. Почему вы считали себя большим специалистом по отладке?
Армстронг: Мне страшно нравилось заниматься отладкой. В какой-то точке программы распечатываешь переменные, что-то еще и смотришь, совпадает ли результат с ожидаемым. В одной точке программа может быть правильной, а в другой - нет. Надо смотреть посередине, потом еще раз посередине и так далее. При условии, что можно воспроизвести ошибку. Невоспроизводимые ошибки с трудом поддаются отладке. Но я сталкивался только с воспроизводимыми. Делишь участок кода пополам каждый раз, пока не найдешь. В конце концов ошибка обнаружится.
Сейбел: Считаете ли вы, что у вас был более систематический подход?
Армстронг: Да, другие попросту сдавались, неясно почему. Я не понимал, почему они не могут отладить. Как вы полагаете, отладка - трудное дело? По-моему, нет. Просто останавливаешь программу и прокручиваешь в замедленном режиме. Я сейчас говорю о пакетном Фортране.
Конечно, если говорить об отладке систем реального времени или программ чистки памяти, то я помню, как однажды “упал” Erlang. Это было в самом начале, сразу после запуска, я сидел и что-то настукивал - и Erlang “упал”. У него в оболочку было встроено что-то вроде команд Emacs. Набираешь erl, чтобы запустить его, и оказываешься в REPL[58]. Я набрал четыре-пять символов и сделал орфографическую ошибку. Потом я несколько раз сдвинул курсор назад, исправил, и он “упал” с ошибкой сборки мусора. Я знал, что это была очень, очень серьезная ошибка. Я попытался в точности вспомнить, что я настукивал, - там было около 12 символов - начал сначала, набил их, и все пошло без сбоя. Я сидел часа полтора, пробуя сотню разных штук. И вот снова сбой! Тут я все записал и смог приступить к отладке.
Сейбел: А чем вы пользуетесь? Операторами печати?
Армстронг: Да. Великие боги программирования говорят: “Вставь оператор печати в программу там, где, по-твоему, допущена ошибка, ре-компилируй и запусти”.
Еще есть Закон отладки Джо - не помню, вычитал я его где-то или сам придумал. Звучит он так: “Все ошибки будут не дальше трех операторов в ту или другую сторону от места последнего изменения программы”. Когда я работал в Шведской космической корпорации, мой начальник там раньше занимался “железом”. Мы были вместе с ним в Эсранге на севере Швеции - там площадка для запуска ракет и станция слежения за спутниками. Как-то раз он ломал голову, отлавливая ошибку в оборудовании, подсоединяя осциллографы, что-то меняя. Я спросил: “Может, я могу чем-нибудь помочь?” От ответил: “Нет, Джо, это ведь железо”. Тогда я сказал: “Это должно быть как в программах - ошибка недалеко от места последнего изменения”. Он подумал и сказал: “Ты гений! Я же поменял конденсатор”. Дело в том, что он заменил конденсатор на другой, более крупный. Мой шеф отпаял его, поставил тот, что был вначале, и все заработало. И это верно для всего. Ремонтируешь машину, что-то не так - причина в последнем действии. Всегда вспоминайте, что вы поменяли.
Сейбел: Вы доказывали когда-нибудь корректность своих программ? Импонирует ли вам такой формализм?
Армстронг: И да и нет. Я преобразовывал программы алгебраически, чтобы показать, что они эквивалентны, но никогда не применял доказательство через теоремы как таковое. Помню, когда я читал курс денотационной семантики, то отказался от этой идеи. Было дано упражнение: пусть