Реферат: М. Бен-Ари Языки программирования. Практический сравнительный анализ. Предисловие


М. Бен-Ари Языки программирования. Практический сравнительный анализ.

Предисловие


Значение языков программирования


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

Роль языка в программировании принижается по сравнению с программной методологией и инструментальными средствами; и не только преуменьшается, но и полностью отвергается, когда утверждают, что хорошо разработанная система может быть одинаково хорошо реализована на любом языке. Но языки программирования — это не просто инструментальное средство;

это тот «материал», из которого создается программное обеспечение, то, что мы видим на наших экранах большую часть дня. Я верю, что язык программирования — один из наиболее, а не наименее важных факторов, которые влияют на окончательное качество программной системы. К сожалению, слишком у многих программистов нет достаточных языковых навыков. Они страстно любят свой «родной» язык программирования и не способны ни проанализировать и сравнить конструкции языка, ни оценить преимущества и недостатки современных языков и языковых понятий. Слишком часто можно услышать утверждения, демонстрирующие концептуальную путаницу: «Язык L1мощнее (или эффективнее) языка L2».

С этим недостатком знания связаны две серьезные проблемы разработки программного обеспечения. Первая — крайний консерватизм в выборе языков программирования. Несмотря на бурное развитие компьютерной техники и сложности современных программных систем, большинство программ все еще пишутся на языках, которые были разработаны около 1970 г., если

не раньше. Многие исследования в области языков программирования никогда не подвергались проверке практикой, и разработчики программ вынуждены с помощью различных инструментальных средств и методологий компенсировать устаревшую языковую технологию. Это примерно то же, что , отказ авиакомпании испытать реактивный лайнер на том основании, что старые винтомоторные самолеты и так могут прекрасно доставить вас куда нужно.

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

Языки программирования существуют только для преодоления разрыва в уровне абстракции между аппаратными средствами и реальным миром. Есть неизбежное противоречие между высшими уровнями абстракции, которые легче понять и безопаснее использовать, и низшими уровнями, более гибки­ми и зачастую допускающими более эффективную реализацию. Чтобы разра­ботать или выбрать язык программирования, следует избрать соответствую­щий уровень абстракции, и нет ничего удивительного в том, что разные про­граммисты предпочитают различные уровни и что какой-либо язык может подходить для одного проекта и не подходить для другого. Программисту сле­дует хорошо понимать степень надежности и эффективности каждой конст­рукции языка.


^ Цель книги

Цель этой книги — научить читателя разбираться в языках программирова­ния, анализируя и сопоставляя языковые конструкции, и помочь ему уяснить:

• Какие альтернативы доступны разработчику языка?

• Как реализуются языковые конструкции?

• Как их следует использовать?

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

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


^ Выбор материала


Автору книги по языкам программирования неизбежно приходится обижать, по крайней мере 3975 из 4000, если не больше, изобретателей различных язы­ков! Я сознательно решил (даже если это обидит 3994 человека) сосредоточить внимание на очень небольшом наборе языков, поскольку уверен, что на их примере смогу объяснить большинство языковых понятий. Другие языки об­суждаются только при демонстрации таких понятий, которые отсутствуют в языках, выбранных для основного рассмотрения.

Значительная часть книги посвящена «заурядным» процедурным (импе­ративным, imperative) языкам; из этого класса выбраны два. Языки с низким уровнем абстракции представляет С, который обошел Fortran, прежде доми­нирующий в этой категории. Для представления более высокого уровня аб­стракции мы выбрали язык Ada с гораздо более четкими определениями, чем в широко известном языке Pascal.

Этот выбор оправдывает также то, что оба языка имеют расширения (C++ и Ada 95), которые можно использовать для изучения языковой поддержки объектно-ориентированного метода программирования, доминирующего в настоящее время.

К сожалению, (как я полагаю) большинство программ сегодня все еще пишутся на процедурных языках, но за последние годы качество реализаций непроцедурных (неимперативных) языков улучшилось настолько, что они могут использоваться для разработки «реального» программного обеспече­ния. В последних главах представлены функциональные (ML) и логические (Prolog) языки программирования с целью убедить учащихся, что процедур­ные языки не являются концептуальной необходимостью для программиро­вания.

Теория синтаксиса языков программирования и семантики выходит за рамки этой книги. Эти важные предметы лучше оставить для более продви­нутых курсов.

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


^ О чем эта книга


Часть 1 является описательной. Она содержит определения и обзор языков и сред программирования. Во второй части подробно объясняются основные конструкции языков программирования: типы, операторы и подпрограммы. В части 3 рассматриваются более сложные понятия программирования, та­кие, как действительные числа, статический полиморфизм, обработка оши­бок и параллелизм. В части 4 обсуждается программирование больших систем с акцентом на языковой поддержке объектно-ориентированного программи­рования. Заключительная часть 5 посвящена основным концепциям функци­онального и логического программирования.


^ Рекомендации по обучению


Необходимое условие для изучения этой книги — по крайней мере один год программирования на каком-либо языке типа Pascal или С. В любом случае, студент должен уметь читать С-программы. Также будет полезно знакомство со структурой и набором команд какого-либо компьютера.

На основе изложенного материала можно составить несколько курсов лек­ций. Части 1 и 2 вместе с разделами части 4 по модулям и объектно-ориенти­рованному программированию могут послужить основой односеместрового курса лекций для второкурсников. Для продвинутых студентов можно уско­рить изложение первой половины, с тем чтобы сосредоточиться на более трудном материале в частях 3 и 4. Углубленный курс, несомненно, должен включить часть 5, дополненную в большом объеме материалом по некоторо­му непроцедурному языку, выбранному преподавателем. Разделы, отмечен­ные звездочкой, ориентированы на продвинутых студентов.

Для большинства языков можно бесплатно получить компиляторы, как описано в приложении А. Студенты также должны быть обучены тому, как просмотреть команды ассемблера, генерируемые компиляторами.

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

Книга будет также полезна программистам, которые хотят углубить свои знания об инструменте, которым они ежедневно пользуются, — о языках про­граммирования.


^ Примечание автора

Лично я предпочитаю более высокие уровни абстракции низким. Это — убеждение, а не предубеждение. Нам — разработчикам программного обес­печения — принадлежат печальные рекорды в вопросах разработки надеж­ных программных систем, и я полагаю, что решение отчасти лежит в пере­ходе к языкам программирования более высоких уровней абстракции. Обоб­щая высказывание Дейкстры, можно утверждать: если у вас есть программа в 100 000 строк, в которой вы запутались, то следует переписать ее в виде про­граммы в 10 000 строк на языке программирования более высокого уровня.

Первый опыт я получил в начале 1970-х годов как член большой группы программистов, работающих над системой финансовых транзакций. Мы ус­тановили новую интерактивную систему, хотя знали, что она содержала ошибку, которую мы не могли найти. Спустя несколько недель ошибка была, наконец, обнаружена: оказалось, что изъяны в используемом языке програм­мирования привели к тому, что тривиальная опечатка превратилась в несоот­ветствие типов. Пару лет спустя, когда я впервые увидел Pascal, меня «зацепи­ло». Мое убеждение в важности проблемы усиливалось всякий раз, когда я по­могал ученому, потратившему впустую недели на отыскание ошибки в про­грамме, причем в такой, которую, будь она на языке Pascal, нельзя было бы даже успешно скомпилировать. Конечно, несоответствие типов — не единст­венный источник ошибок программирования, но оно настолько часто встре­чается и так опасно, хотя и легко обнаруживается, что я считаю жесткий кон­троль соответствия типов столь же необходимым, как и ремень безопасности в автомобиле: использование его причиняет неудобство, но оно весьма незна­чительно по сравнению с возможным ущербом, а ведь даже самые лучшие во­дители могут попасть в аварию.

Я не хочу быть вовлеченным в языковые «войны», утверждая, что один язык лучше другого для какой-либо определенной машины или прикладной программы. Я попытался проанализировать конструкции языка по возмож­ности объективно в надежде внести вклад в повышение уровня научных дис­куссий относительно языков программирования.


Благодарности


Я хотел бы поблагодарить Кевлина А.П. Хеннея (Kevlin A.P Неппеу) и Дэ­вида В. Баррона (David W. Barron) за ценные замечания по всей рукописи, так же как Гарри Майрсона (Harry Mairson), Тамара Бенея (Tamar Benaya) и Бруриа Хабермена (Bruria Haberman), которые прочитали отдельные ча­сти. Я обязан Амирему Ехудаи (Amiram Yehudai), моему гуру в объектно-ориентированном программировании: он руководил мной во время много­численных обсуждений и тщательно проверял соответствующие главы. Эдмон Шенберг (Edmond Schonberg), Роберт Девар (Robert Dewar) вместе со своей группой в NYU быстро отвечали на мои вопросы по GNAT, позволив мне обучиться и написать о языке Ada 95 еще до того, как стал доступен полный компилятор. Ян Джойнер (lan Joyner) любезно предоставил свой неопубликованный анализ языка C++, который был чрезвычайно полезен. Подобно моим предыдущим книгам, эта, вероятно, не была бы написана без LATEX Лесли Лампорта (Leslie Lamport)!

Мне посчастливилось работать с высоко профессиональной, квалифици­рованной издательской группой Джона Уайли (John Wiley), и я хотел бы по­благодарить всех ее членов и особенно моего редактора Гейнора Редвеса-Мат-тона (Gaynor Redvers-Mutton).


^ М. Бен-Ари


Реховот, Израиль


1 Введение

в языки

программирования


Глава 1

Что такое

языки программирования


1.1. Некорректный вопрос


Первый вопрос, который обычно задает человек, впервые сталкивающийся с новым языком программирования:

Что этот язык может «делать»?

Неявно мы сравниваем новый язык с другими. Ответ очень прост: все язы­ки могут «делать» одно и то же — производить вычисления! В разделе 1.8 объ­яснена правомерность такого ответа. Однако, если все они могут выполнять одно и то же — вычисления — то, несомненно, причины существования сотен языков программирования должны быть в чем-то другом.

Позвольте начать с нескольких определений:


Программа — это последовательность символов, определяющая вычисление.


^ Язык программирования — это набор правил, определяющих, какие по­следовательности символов составляют программу и какое вычисление описывает программа.


Вас может удивить, что в определении не упоминается слово «компьютер»! Программы и языки могут быть определены как сугубо формальные матема­тические объекты. Однако люди больше интересуются программами, чем другими математическими объектами типа групп, именно потому, что про­грамму — последовательность символов — можно использовать для управле­ния работой компьютера. Хотя мы настоятельно рекомендуем изучение тео­рии программирования, здесь ограничимся, в основном, изучением того, как программы выполняются на компьютере.

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

Чтобы ответить на вопрос, вынесенный в название главы, вернемся к пер­вым цифровым компьютерам, очень похожим на простые калькуляторы, ка­кими сегодня пользуются для расчетов в магазине. Они работали по «жест­кой» программе, которую нельзя изменить.

Наиболее значительным из первых шагов в усовершенствовании компью­теров была идея (автором которой считается Джон фон Нейман) о том, что описание вычисления (программу) можно хранить в памяти компьютера так же, как данные. Компьютер с запоминаемой программой, таким образом, стано­вится универсальной вычислительной машиной, а программу можно изме­нять, только заменяя коммутационную доску, вводя перфокарты, вставляя дискету или подключаясь к телефонной линии.

Поскольку компьютеры — двоичные машины, распознающие только нули и единицы, то хранить программы в компьютере технически просто, но прак­тически неудобно: каждая команда должна быть записана в виде двоичных цифр (битов), которые можно представить механически или электрически. Одним из первых программных средств был символический ассемблер. Ассемб­лер берет программу, написанную на языке ассемблера (каждая команда пред­ставлена в нем в символьном виде), и транслирует символы в двоичное пред­ставление, пригодное для выполнения на компьютере. Например, команду


load R3,54


означающую «загрузить в регистр 3 данные из ячейки памяти 54», намного легче прочитать, чем эквивалентную последовательность битов. Трудно пове­рить, но термин «автоматическое программирование» первоначально отно­сился к ассемблерам, так как они автоматически выбирали правильную по­следовательность битов для каждого символа. Известные языки программи­рования, такие как С и Pascal, сложнее ассемблерных языков, потому что они «автоматически» выбирают адреса и регистры и даже «автоматически» выби­рают последовательности команд для организации циклов и вычисления арифметических выражений.

Теперь мы готовы ответить на вопрос из названия этой главы.


Язык программирования — это механизм абстрагирования. Он дает воз­можность программисту описать вычисления абстрактно и в то же вре­мя позволяет программе (обычно называемой ассемблером, компилято­ром или интерпретатором) перевести это описание в детализированную форму, необходимую для выполнения на компьютере.


Теперь понятно, почему существуют сотни языков программирования: для двух разных классов задач скорее всего потребуются различные уровни абстракции, и у разных программистов будут различные представления о том, какими должны быть эти абстракции. Программист, работающий на С, впол­не доволен работой на уровне абстракции, требующем определения вычисле­ний с помощью массивов и индексов, в то время как составитель отчета отда­ет предпочтение «программе» на языке, содержащем функции текстовой об­работки.

Уровни абстракции легко различить в компьютерных аппаратных средст­вах. Первоначально монтажные соединения непосредственно связывали дис­кретные компоненты, такие как транзисторы и резисторы. Затем стали ис­пользоваться стандартные подсоединяемые с помощью разъемов модули, за которыми последовали небольшие интегральные схемы. Сегодня компьюте­ры целиком собираются из горстки чипов, каждый из которых содержит сот­ни тысяч компонентов. Никакой компьютерщик не рискнул бы разрабаты­вать «оптимальную» схему из индивидуальных компонентов, если существует набор подходящих чипов, которые выполняют нужные функции.

Из концепции абстракции вытекает общее правило:


^ Чем выше уровень абстракции, тем больше деталей исчезает.


Если вы пишете программу на С, то теряете возможность задать распреде­ление регистров, которая есть в языке ассемблера; если вы пишете на языке Prolog, то теряете имеющуюся в С возможность определить произвольные связанные структуры с помощью указателей. Существует естественное проти­воречие между стремлением к краткому, ясному и надежному выражению вы­числения на высокоабстрактном уровне и стремлением к гибкости подробно­го описания вычисления. Абстракция никогда не может быть такой же точной или оптимальной, как описание низкого уровня.


В этом учебнике вы изучите языки трех уровней абстракции. Опуская ас­семблер, мы начнем с «обычных» языков программирования, таких как Fortran, С, Pascal и Pascal-подобные конструкции языка Ada. Затем в части 4 мы обсудим языки типа Ada и С ++, которые позволяют программисту созда­вать абстракции более высокого уровня из операторов обычных языков. В за­ключение мы опишем языки функционального и логического программиро­вания, работающие на еще более высоком уровне абстракций.

^ 1.2. Процедурные языки


Fortran


Первым языком программирования, который значительно превзошел уро­вень языка ассемблера, стал Fortran. Он был разработан в 1950-х годах груп­пой специалистов фирмы IBM во главе с Джоном Бекусом и предназначался для абстрактного описания научных вычислений. Fortran встретил сильное противодействие по тем же причинам, что и все последующие предложения абстракций более высокого уровня, а именно из-за того, что большинство программистов полагало, что сгенерированный компилятором программный код не может быть лучше написанного вручную на языке ассемблера.

Подобно большинству первых языков программирования, Fortran имел серьезные недостатки в деталях самого языка, и, что важнее, в нем отсутство­вала поддержка современных концепций структурирования модулей и дан­ных. Сам Бекус, оглядываясь назад, говорил:


Мы просто придумывали язык по мере его осмысления. Мы расценива­ли проектирование языка не как трудную задачу, а просто как прелюдию к реальной проблеме: проектированию компилятора, который мог бы генерировать эффективные программы.


Однако преимущества абстракции быстро покорили большинство про­граммистов: разработка программ стала более быстрой и надежной, а их машинная зависимость уменьшилась из-за абстрагирования от регистров и машинных команд. Поскольку самыми первыми на компьютерах рассчитыва­лись научные задачи, Fortran стал стандартным языком в науке и технике, и только теперь на смену ему приходят другие языки. Fortran был неоднократно модернизирован (1966,1977,1990) с тем, чтобы адаптировать его к требовани­ям современных программных разработок.


^ Cobol и PL/1


Язык Cobol был разработан в 1950-х для обработки коммерческих данных. Он создавался комитетом, состоящим из представителей Министерства Обороны США, производителей компьютеров и коммерческих организаций типа стра­ховых компаний. Предполагалось, что Cobol — это только временное решение, необходимое, пока не создан лучший проект; однако язык быстро стал самым распространенным в своей области (как Fortran в науке), причем по той же самой причине: он обеспечивал естественные средства выражения вычисле­ний, типичных для своей области. При обработке коммерческих данных не­обходимо делать относительно простые вычисления для большого числа сложных записей данных, а по возможностям структурирования данных Cobol намного превосходит алгоритмические языки типа Fortran или С.

IBM позже создала язык PL/1, универсальный, обладающий всеми свой­ствами языков Fortran, Cobol и Algol. PL/1 заменил Fortran и Cobol на мно­гих компьютерах IBM, но этот язык очень широкого диапазона никогда не поддерживался вне IBM, особенно на мини- и микроЭВМ, которые все больше и больше используются в организациях, занимающихся обработкой данных.


^ Algol и его потомки


Из ранних языков программирования Algol больше других повлиял на созда­ние языков. Разработанный международной группой первоначально для об­щих и научных приложений, он никогда не достигал такой популярности, как Fortran, поскольку не имел той поддержки, которую Fortran получил от боль­шинства производителей компьютеров. Описание первой версии языка Algol было опубликовано в 1958 г.; пересмотренная версия, Algol 60, широко ис­пользовалась в компьютерных научных исследованиях и была реализована на многих машинах, особенно в Европе. Третья версия языка, Algol 68, пользова­лась влиянием среди теоретиков по языкам, хотя никогда широко не приме­нялась.

От языка Algol произошли два важных языка: Jovial, который использовался Военно-воздушными силами США для систем реального времени, и Simula, один из первых языков моделирования. Но, возможно, наиболее известным его потомком является Pascal, разработанный в конце 1960-х Никлаусом Виртом. Целью разработки было создание языка, который можно было бы использовать для демонстрации идей объявления типов и контроля их соответствия. В после­дующих главах мы докажем, что эти концепции относятся к наиболее важным, когда-либо предлагавшимся в проектировании языков.

Как язык практического программирования Pascal имеет одно большое преимущество и один большой недостаток. Первоначальный компилятор языка Pascal был написан на самом языке Pascal и, таким образом, мог быть легко перенесен на любой компьютер. Язык распространялся быстро, особен­но на создаваемых в то время мини- и микроЭВМ. К сожалению, как язык, Pascal слишком мал. Стандартный Pascal вообще не имеет никаких средств для деления программы на модули, хранящиеся в отдельных файлах, и поэто­му не может использоваться для программ объемом больше нескольких тысяч строк. Компиляторы Pascal, используемые на практике, поддерживают деком­позицию на модули, но никаких стандартных методов для этого не существу­ет, так что большие программы непереносимы. Вирт сразу понял, что модули являются необходимой частью любого практического языка, и разработал язык Modula. Modula (теперь в версии 3, поддерживающей объектно-ориенти­рованное программирование) — популярная альтернатива нестандартным «диалектам» языка Pascal.


С


Язык С был разработан в начале 1970-х Деннисом Ричи, сотрудником Bell Laboratories, как язык реализации операционной системы UNIX. Операцион­ные системы традиционно писали на ассемблере, поскольку языки высокого уровня считались неэффективными. Язык С абстрагируется от деталей программирования, присущих ассемблерам, предлагая структурированные управ­ляющие операторы и структуры данных (массивы и записи) и сохраняя при этом всю гибкость ассемблерного низкоуровневого программирования (указа­тели и операции на уровне битов).

Так как система UNIX была легко доступна для университетов и написана на переносимом языке, а не на языке ассемблера, то она быстро стала популярна в академических и исследовательских учреждениях. Когда новые компьютеры и прикладные программы выходили из этих учреждений на коммерческий рынок, вместе с ними распространялись UNIX и С.

Язык С проектировался так, чтобы быть близким к языку ассемблера, и это обеспечивает ему чрезвычайную гибкость; но проблема состоит в том, что эта гибкость обусловливает чрезвычайную легкость создания программ со скрытыми ошибками, поскольку ненадежные конструкции не проверяются компилятором, как это делается на языке Pascal. Язык С — тонкий инстру­мент в руках профессионала и удобен для небольших программ, но при разра­ботке на нем больших программных систем группами разработчиков разной квалификации могут возникнуть серьезные проблемы. Мы отметим многие опасные конструкции С и укажем, как не попадать в главные ловушки.


Язык С был стандартизирован в 1989 г. Американским Национальным Ин­ститутом Стандартов (ANSI); практически тот же самый стандарт был принят Международной Организацией по Стандартизации (ISO) годом позже. В этой книге делаются ссылки на ANSI С, а не на более ранние версии языка.


C++


В 1980-х годах Бьярн Строуструп, также из Bell Laboratories, использовал С как базис языка C++, добавив поддержку объектно-ориентированного програм­мирования, аналогичную той, которую предоставлял язык Simula. Кроме то­го, в C++ исправлены многие ошибки языка С, и ему следует отдавать пред­почтение даже в небольших программах, где объектно-ориентированные свойства, возможно, и не нужны. C++ — наиболее подходящий язык для об­новления систем, написанных на С.

Обратите внимание, что C++ — развивающийся язык, и в вашем справоч­ном руководстве или компиляторе, возможно, отсутствуют последние изме­нения. Обсуждаемый в этой книге язык соответствует книге Annotated C++ Reference Мanual Эллиса и Строуструпа (издание 1994 г.), которая является ос­новой рассматриваемого в настоящее время стандарта.


Ada


В 1977 г. Министерство Обороны Соединенных Штатов решило провести унификацию языка программирования, в основном, чтобы сэкономить на обучении и стоимости поддержки операционных сред разработки программ для различных военных систем. После оценки существующих языков было принято решение провести конкурс на разработку нового языка, положив в основу хороший существующий язык, такой как Pascal. В конце концов был выбран язык, который назвали Ada, и стандарт был принят в 1983 г. Язык Ada уникален в ряде аспектов:


• Большинство языков (Fortran, С, Pascal) создавались едиными ко­мандами разработчиков и были стандартизованы уже после их широкого распространения. Для сохранения совместимости все случайные прома­хи исходной команды включались в стандарт. Ada же перед стандартиза­цией подверглась интенсивной проверке и критическому разбору.


• Многие языки первоначально были реализованы на единственном ком­пьютере, и на них сильно повлияли особенности этого компьютера. Язык Ada был разработан для написания переносимых программ.


• Ada расширяет область применения языков программирования, обеспечи­вая обработку ошибок и параллельное программирование, что традицион­но считалось (нестандартными) функциями операционных систем.


Несмотря на техническое совершенство и преимущества ранней стандар­тизации, язык Ada не достиг большой популярности вне военных и других крупномасштабных проектов (типа коммерческой авиации и железнодорож­ных перевозок). Язык Ada получил репутацию трудного. Это связано с тем, что он поддерживает многие аспекты программирования (параллелизм, обра­ботку исключительных ситуаций, переносимые числовые данные), которые другие языки (подобные С и Pascal) оставляют операционной системе. На са­мом деле его нужно просто больше изучать. К тому же первоначально были недоступны хорошие и недорогие среды разработки для сферы образования. Теперь, когда есть бесплатные компиляторы (см. приложение А) и хорошие учебники, Ada все чаще и чаще встречается в учебных курсах даже как «пер­вый» язык.


Ada 95


Ровно через двенадцать лет после принятия в 1983 г. первого стандарта языка Ada был издан новый стандарт. В новой версии, названной Ada 95, исправле­ны некоторые ошибки первоначальной версии, но главное — это добавление поддержки настоящего объектно-ориентированного программирования, включая наследование, которого не было в Ada 83, так как его считали неэф­фективным. Кроме того, Ada 95 содержит приложения, в которых описываются стандартные (но необязательные) расширения для систем реального вре­мени, распределенных систем, информационных систем, защищенных сис­тем, а также «числовое» (numerics) приложение.

В этой книге название «Ada» будет использоваться в тех случаях, когда об­суждение не касается особенностей одной из версий: Ada 83 или Ada 95. Заме­тим, что в литературе Ada 95 упоминалась как Ada 9X, так как во время разра­ботки точная дата стандартизации не была известна

.

^ 1.3. Языки, ориентированные на данные


На заре программирования было создано и реализовано несколько языков, значительно повлиявших на дальнейшие разработки. У них была одна общая черта: каждый язык имел предпочтительную структуру данных и обширный набор команд для нее. Эти языки позволяли создавать сложные программы, которые трудно было бы написать на языках типа Fortran, просто манипули­рующих компьютерными словами. В следующих подразделах мы рассмотрим некоторые из этих языков.


Lisp


Основная структура данных в языке Lisp — связанный список. Первоначаль-но Lisp был разработан для исследований в теории вычислений, и многие ра­боты по искусственному интеллекту были выполнены на языке Lisp. Язык был настолько важен, что компьютеры разрабатывались и создавались так, чтобы оптимизировать выполнение Lisp-программ. Одна из проблем языка состояла в обилии различных «диалектов», возникавших по мере того, как язык реализовывался на различных машинах. Позже был разработан стандар­тный язык Lisp, чтобы программы можно было переносить с одного компью­тера на другой. В настоящее время популярен «диалект» языка Lisp — CLOS, поддерживающий объектно-ориентированное программирование.

Три основные команды языка Lisp — это car(L) и cdr(L), которые извлека­ют, соответственно, начало и конец списка L, и cons(E, L), которая создает но­вый список из элемента Е и существующего списка L. Используя эти коман­ды, можно определить функции обработки списков, содержащих нечисловые данные; такие функции было бы довольно трудно запрограммировать на языке Fortran.

Мы не будем больше обсуждать язык Lisp, потому что многие его основополагающие идеи были перенесены в современные функциональные языки программирования типа ML, который мы обсудим в гл. 16.


APL


Язык APL является развитием математического формализма, который ис­пользуется для описания вычислений. Основные структуры данных в нем — векторы и матрицы, и операции выполняются над такими структурами непо­средственно, без циклов. Программы на языке APL очень короткие по срав­нению с аналогичными программами на традиционных языках. Применение APL осложняло то, что в язык перешел большой набор математических сим­волов из первоначального формализма. Это требовало специальных термина­лов и затрудняло экспериментирование с APL без дорогостоящих аппаратных средств. Современные графические интерфейсы пользователя, применяю­щие программные шрифты, решили эту проблему, которая замедляла приня­тие APL.


Предположим, что задана векторная переменная:


V= 1 5 10 15 20 25


Операторы языка APL могут работать непосредственно с V без записи цик­лов с индексами:


+ /V =76 Свертка сложением(суммирует элементы)

фV = 25 20 15 10 5 1 Обращает вектор


2 3 pV = 1 5 10 Переопределяет размерность

V 15 20 25 как матрицу 2x3

Векторные и матричные сложения и умножения также можно выполнить непосредственно над такими переменными.


^ Snobol, Icon


Первые языки имели дело практически только с числами. Для работы в таких областях, как обработка естественных языков, идеально подходит Snobol (и его преемник Icon), поскольку их базовой структурой данных является стро­ка. Основная операция в языке Snobol сравнивает образец со строкой, и по­бочным результатом совпадения может быть разложение строки на подстро­ки. В языке Icon основная операция — вычисление выражения, причем выра­жения включают сложные операции со строками.

В языке Icon есть важная встроенная функция find(s1, s2), которая ищет вхождения строки s1 в строку s2. В отличие от подобных функций языка С find генерирует список всех позиций в s2, в которых встречается s1:


line := 0 # Инициализировать счетчик строк while s := read() { # Читать до конца файла

every col := find("the", s) do # Генерировать позиции столбца write (line, " ",col) # Write(line,col) для "the"

line := line+ 1

}


Эта программа записывает номера строк и столбцов всех вхождений стро­ки "the" в файл. Если команда find не находит ни одного вхождения, то она «терпит неудачу» (fail), и вычисление выражения завершается. Ключевое сло­во every вызывает повторение вычисления функции до тех пор, пока оно за­вершается успешно.

Выражения Icon содержат не только строки, которые представляют собой последовательности символов; они также определены над наборами символов csets. Таким образом


vowels := 'aeiou'

присваивает переменной vowel (гласные) значение, представляющее собой набор указанных символов. Это можно использовать в функциях типа upto(vowels,s), генерирующих последовательность позиций гласных в s, и many(vowels,s), возвращающих самую длинную начальную последователь­ность гласных в s.

Более сложная функция bal подобна upto за исключением того, что она ге­нерирует последовательности позиций, которые сбалансированы по «ско­бочным» символам:


bal(' +-*/','([', ')]',*)


Это выражение могло использоваться в компиляторе, чтобы генериро­вать сбалансированные арифметические подстроки. Если в качестве строки s задать

"х + (у [u/v] - 1 )*z", вышеупомянутое выражение сгенерирует индек­сы, соответствующие подстрокам:


x


x+(y[u/v]-1


Первая подстрока сбалансирована, так как она заканчивается «+» и не содержит никаких скобок; вторая подстрока сбалансирована, поскольку она завершается символом «*» и имеет квадратные скобки, правильно вложенные внутри круглых скобок.
Глава 2

Элементы

языков программирования


2.1. Синтаксис


Как и у обычных языков, у языков программирования есть синтаксис:


Синтаксис языка (программирования) — это набор правил, которые опре­деляют, какие последовательности символов считаются допустимыми вы­ражениями (программами) в языке.


Синтаксис задается с помощью формальной нотации.

Самая распространенная формальная нотация синтаксиса — это расширен­ная форма Бекуса — Наура (РБНФ). В РБНФ мы начинаем с объекта самого верхнего уровня, с программы, и применяем правила декомпозиции объектов, пока не достигнем уровня отдельного символа. Например, в языке С синтак­сис условного оператора (if-оператора) задается правилом:

if-onepamop :: = if (выражение) оператор [else оператор]


Имена, выделенные курсивом, представляют синтаксические категории, а имена и символы, выделенные полужирным шрифтом, представляют факти­ческие символы, которые должны появиться в программе. Каждое правило содерж
еще рефераты
Еще работы по разное