Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Языки программирования. Концепции и принципы
.pdf
Важнейшие абстракции: данные, операции, связывание
Рассмотрим ряд примеров, подтверждающих принцип относительности и
единства выделенных абстракций. Покажем, что он не только объясняет появле
ние и смысл языковых конструктов, но и указывает перспективы их развития.
Так, хороший стиль программирования предполагает, что когда вводят опера
ционную абстракцию (процедуру, функцию, операцию), то явно указывают ха
рактеристики данных, к которым ее можно применять (с которыми ее можно свя
зывать). Например, специфицируют параметры процедуры (как мы и поступали
в задаче об управлении сетью). Такую спецификацию можно назвать специфика
цией операции по данным извне (со стороны использования). Когда реализуют
введенную операционную абстракцию (проще говоря, программируют процедуру
или функцию), то также указывают характеристики данных (на этот раз исполь
зуемых, подчиненных, желательно локальных; в нашем примере это был тип
запись_об_узле). Такую спецификацию можно назвать спецификацией операции
по данным изнутри (со стороны реализации).
Вопрос. Когда полезна такая спецификация?
Подсказка. Ведь это, в сущности, заказ ресурсов, который необходим для их раци
онального распределения, особенно в режиме разделения ресурсов между парал
лельными процессами.
В современных ЯП (в том числе в Аде), когда вводят абстракцию данных (пе
ременнную, тип переменнных), то указывают класс операций, связываемых с этой
абстракцией (определяют абстрактный тип данных, АТД). Это можно назвать
спецификацией данных по операциям извне (со стороны использования). В на
шем примере это пять операций – вставить, удалить, связать, все_связи и узел_есть,
характеризующих доступ к абстрактной переменной «сеть». Из соображений
симметрии следовало бы рассматривать и данные (абстракции данных), для реа
лизации которых нужны внутренние (локальные) операции. Это была бы специ
фикация данных по операциям изнутри.
71
Вопрос. Зачем могут понадобиться такие спецификации?
Подсказка. Представьте «живые» данные, отражающие состояние взаимодей
ствующих процессов. Какие операции потребуются, чтобы их реализовать? Какой
должна быть среда, в которую можно перенести такие данные? Конкретный при
мер – монитор ХоараХансена, о котором пойдет речь в главе об асинхронных про
цессах. Для его реализации требуются операции над сигналами, семафорами или
рандеву.
3.2. Связывание
Так как выделение связывания в качестве самостоятельной абстракции менее
традиционно, полезно рассмотреть его подробнее и проиллюстрировать плодо
творность этого выделения нетривиальными применениями.
В самом общем понимании связывание неотличимо от установления соответ
ствия, сопоставления, отношения. Однако в применении к программированию

72
нас интересует определенный набор выразительных средств, управляющих свя
зыванием и пригодных для реализации на компьютерах. Поэтому, говоря о связы
вании здесь, мы подразумеваем аппарат, действующий в рамках существующей
или потенциальной системы программирования и предназначенный для органи
зации взаимодействия операций и данных.
Постараемся показать, вопервых, что абстракция связывания помогает с еди
ных позиций понимать кажущиеся совершенно различными сущности, и, вовто
рых, что выделение такой абстракции помогает увидеть возможные направления
развития ЯП.
Для начала подчеркнем, что в качестве составляющих единого аппарата связы
вания в системе программирования естественно рассматривать редактор связей,
загрузчик, оптимизатор, компилятор, интерпретатор и другие системные сред
ства, предназначенные для подготовки программы к выполнению. Ведь все эти
средства участвуют в различных этапах окончательного связывания конкретных
операций с конкретными операндами.
Итак, можно говорить о связывании загрузочных модулей для последующего
совместного использования. Такая работа выполняется редактором связей. Мож
но говорить о связывании аргументов подпрограммы с ее телом для последующе
го совместного выполнения. Такое связывание обеспечивается вызовом и заго
ловком подпрограммы. Вполне разумно говорить и о связывании отдельных
компонент объектной программы в процессе ее трансляции с ЯП. Выполняется
оно, естественно, транслятором.
Отметим важный аспект. Связывание может распадаться на этапы, выполняе
мые на различных стадиях подготовки того конкретного акта исполнителя, ради
которого это связывание в конечном итоге осуществляется. Например, трансли
ровать можно за несколько проходов; связать загрузочные модули можно частич
но редактором связей, частично загрузчиком; при обращении к программе часть
работы по связыванию можно выполнить при обращении к подпрограмме, часть –
при выполнении ее тела (именно распределением работы по связыванию отлича
ются различные способы вызова параметров – наименованием, значением, ссыл
кой и др.).
Повидимому, все эти примеры хорошо известны. Но общая концепция свя
зывания способна привести и к совершенно новому понятию, отсутствующему
в традиционных ЯП.
Современное состояние языков программирования
3.3. От связывания к пакету
Из общего курса программирования известно, что такое контекст. Известно так
же, что модуль – это программа, рассчитанная на многократное использование
в различных контекстах (и для этого соответствующим образом оформленная).
В традиционных ЯП контекст задается обычно совокупностью объявлений (опи
саний) некоторого блока или подпрограммы и связывается с телом блока тексту
ально, физическим соединением тела и контекста. Но если модуль рассчитан на
различные контексты, то и контекст, естественно, может оказаться пригодным

Важнейшие абстракции: данные, операции, связывание
для работы с различными модулями. Следовательно, хорошо бы и контекст оформ
лять по таким правилам, чтобы его не нужно было выписывать каждый раз,
а можно было использовать как модуль, связывая с телом блока, например, во вре
мя трансляции, Подобной категории модулей ни в Алголе, ни в Фортране, ни
в Паскале нет. Впервые такой модуль появился в языке Симула67 и был назван
«классом». В Аде его аналог назван «пакетом».
Рассмотрим подробнее путь к пакету на конкретном примере.
В общем курсе программирования при изучении структур данных знакомят
с совокупностью понятий, позволяющих работать со строками. Например, опре
деляют представление строк одномерными массивами и предоставляют несколь
ко операций над строками (например, встроку, изстроки и подстрока). Спраши
вается, каким образом оформить это интеллектуальное богатство так, чтобы им
было удобно пользоваться? Алгол60 или Паскаль позволяет записать соответ
ствующие объявления массивов и процедур, а тем самым сделать их известными
многим программистам. Совокупность указанных объявлений массивов, пере
менных и процедур, выписанная в начале блока, позволяет в теле блока работать
в сущности на языке, расширенном по сравнению с Алголом60 (понятием строч
ных переменных и набором операций над такими переменными).
Но вот мы знаем (изучили) эти объявления и хотим ими воспользоваться (на
пример, запрограммировать и запустить универсальный нормальный алгоритм
Маркова, как нам предлагают авторы того же курса). Алгол60 заставляет нас пе
реписать в свою программу все нужные объявления. Но это и труд, и ошибки, и
время, и место на носителях. На практике, конечно, во многих реализациях Алго
ла60 есть возможность обращаться к библиотеке, где можно хранить объявления
функций и процедур (но не переменных и массивов). Однако целостного языко
вого средства, обслуживающего потребность делать доступным расширение язы
ка, однажды спроектированное и полностью подготовленное к использованию,
нет. Другими словами, не выделена абстракция связывания компонент потен
циально полезного контекста. Нет ее ни в Паскале, ни в Фортране, хотя общие
объекты последнего – намек на движение в нужном направлении.
Как уже сказано, впервые нужная абстракция была осознана и оформлена со
ответствующим конструктом в языке Симула67. Основная идея в том, что сово
купность объявлений можно синтаксически оформить (в качестве «класса»),
предварив их ключевым словом class и снабдив индивидуальным именем. Так
можно получить, например, класс с именем обработка_строк, в котором будут
объявлены одномерный массив и процедуры для работы с этим массивом как со
строкой символов. Чтобы воспользоваться такими объявлениями (в совокупно
сти!), достаточно перед началом программы указать в качестве приставки имя
нужного класса. Объявления из такого класса считаются выписанными в фиктив
ном блоке, объемлющем создаваемую программу (то есть доступны в ней). На
пример, программу нормального алгоритма достаточно предварить приставкой
обработка_строк.
В первом приближении основная идея ПАКЕТА совпадает с идеей класса –
это также совокупность объявлений, снабженная именем и пригодная для исполь
73

74
зования в качестве «приставки». Однако в понятии «пакет» воплощены и другие
важнейшие идеи, о которых уже шла речь. Подчеркнем, что к новым понятиям нас
привела общая концепция связывания.
Вопрос. Чем идея пакета (модуляконтекста) отличается от идеи простого копиро
вания контекста? От идеи макроопределений?
Подсказка. Важно, когда происходит связывание, а также чего и с чем. Кроме того,
не забывайте об управлении доступом к контексту.
Современное состояние языков программирования
3.4. Связывание и специализация
Не только отдельные языковые конструкты обязаны своим возникновением тому,
что связывание было осознано как самостоятельная абстракция. На его основе
возникло целое направление в программировании – так называемое конкретизи
рующее программирование (как было отмечено, связывание обобщает основные
виды конкретизации). Когда говорят о конкретизирующем программировании,
часто приводят такой пример.
Рассмотрим операцию «**» возведения основания х в степень n. Если понятно
самостоятельное значение связывания, то легко представить себе ситуацию, когда
с операцией «**» уже связан один операнд и еще не связан другой. С точки зрения
итогового возведения в степень, такая ситуация запрещена – еще нельзя совер
шить запланированный акт поведения (операнды не готовы). Но если понимать
связывание как многоэтапный процесс подготовки этого акта, то рассматривае
мая ситуация может соответствовать одному из этапов этого процесса. Более того,
на аналогичном этапе связывания могут задерживаться целые классы таких про
цессов. Это повторяющееся следует выделить, обозначить и применить (пользу
емся одним из важнейших общих принципов абстрагирования – принципом обо
значения повторяющегося). Так получается целый ряд одноместных операций
(«1**»,«2**»,«3**»...) при фиксированном основании и ряд одноместных опера
ций («**1»,«**2»,«**3»...) при фиксированном показателе степени. Но, например,
операцию «**3» можно реализовать просто как х*х*х, что короче, проще и эффек
тивней общей программы для «**».
Таким образом и возникает идея универсального конкретизатора, который по
параметрической программе (например, «**») и некоторым уже связанным с ней
аргументам строит (потенциально более эффективную) конкретизированную
программу (например, «**3»). Если такой конкретизатор удастся построить для
некоторого класса программ, то возникнет надежда обеспечить целую проблем
ную область эффективными и надежными, «по происхождению» правильными
программами. Ведь исходная параметрическая программа предполагается сде
ланной исключительно тщательно (во всяком случае, правильно) – при таком ее
широком назначении на нее не жалко усилий.
В настоящее время конкретизирующее программирование интенсивно разви
вается и у нас, и за рубежом. Конкретизатор в литературе называют иногда специ
ализатором, а также смешанным вычислителем (за то, что он проводит вычисле
ния и над данными, и над программами).

Важнейшие абстракции: данные, операции, связывание
Отметим, что любые языковые конструкты можно при желании считать частью
аппарата связывания. Ведь с их помощью аргументы программы связываются с ее
результатами на той или иной стадии обработки ее текста. Воспользуемся этим
наблюдением, чтобы продемонстрировать еще одно применение аппарата связы
вания, – уточним терминологию и укажем некоторые перспективы в теории
трансляции. Это же наблюдение положено в основу трансформационного подхо
да к программированию [3].
75
3.4.1. Связывание и теория трансляции
Основной результат настоящего раздела: такие программы, как компилятор и су
перкомпилятор (генератор компиляторов), могут быть формально получены из
интерпретатора ЯП с помощью подходящего связывания.
Ключевая идея: следует применить особый вид связывания, обобщающий
обычный вызов функции таким образом, что часть параметров функции оказыва
ется связанной со своими аргументами, а остальные остаются пока несвязанными
и служат параметрами остаточной функции. Остаточной называют функцию, вы
зов которой с оставшимися аргументами эквивалентен вызову исходной функции
с полным набором аргументов. Такой вид связывания называют специализацией.
Число аргументов функции несущественно, важно лишь отделить связывае
мые раньше и позже. Поэтому для уяснения основной идеи достаточно рассмот
реть функции с двумя аргументами.
Введем понятие «универсального специализатора». Вслед за Бэкусом назовем
формой функцию высшего порядка, то есть функцию, аргумент и (или) результат
которой также представляет собой некоторую функцию. «Универсальный специ
ализатор» s – это форма, которая по произвольной функции двух переменных
F(X,Y) и заданному ее аргументу х0 выдает в качестве результата функцию одно
го аргумента s(F,x0), такую, что для всех допустимых значений параметра Y спра
ведливо определяющее соотношение
(**) s(F,x0) (Y) = F(x0,Y),
так что s(F,x0) – это и есть остаточная функция после связывания первого пара
метра функции F с аргументом х0.
Покажем, как получить объявленный основной результат. Допустим, что все
рассматриваемые функции и формы реализованы подходящими программами. Со
храним для этих программ те же обозначения. Так что s(F,x0) можно теперь считать
программой, полученной по исходной программе F с помощью программы s.
Замечание. Важно понимать, что о качестве получаемых специализированных (ос
таточных) программ в определении универсального специализатора ничего не ска
зано. Тривиальное преобразование программ может состоять, например, в том, что
в остаточной программе просто содержится вызов вида F(x0,Y).
Упражнение. Запишите тривиальную остаточную программу на одном из извест
ных вам ЯП.

76
Рассмотрим теперь язык программирования L и его интерпретатор i. С одной
стороны, i – это такая программа, что для всякой правильной программы р на язы
ке L и исходных данных d:
i(p,d) = r,
где r – результат применения программы р к данным d. Другими словами, про
грамма i реализует семантику языка L – ставит в соответствие программе р ре
зультат ее выполнения с данными d. С другой стороны, i – это форма от двух аргу
ментов (а именно так называемая ограниченная аппликация – она применяет
свой первый аргументфункцию р ко второму аргументу d, причем пригодна толь
ко для программ из L).
Интерпретатор может быть реализован аппаратно, то есть быть отдельным
устройством, предназначенным для выполнения программ на L. Однако для нас
интереснее случай, когда интерпретатор реализован программой. Программа эта
написана, конечно, на какомто языке программирования М. Будем считать, что
М отличен от L. Программная реализация интерпретатора интересна именно по
тому, что в этом случае интерпретатор представлен написанным на языке М тек
стомпрограммой, и вполне можно ожидать, что в общем случае из этого текста
можно систематическими преобразованиями получать другие программы. На
пример, программы компилятора и суперкомпилятора, также написанные на язы
ке М.
Мы намерены делать это посредством специализатора s. Для определенности
будем считать, что программаспециализатор s также написана на языке М, при
менима к текстам программ, написанным на М, и выдает в качестве результатов
программы, написанные все на том же языке М.
Специализация интерпретатора. Посмотрим, что собой представляет s(i,p), то
есть во что специализатор s превращает интерпретатор i после его связывания с
конкретной программой р. (Ведь i – форма от двух аргументов, так что специали
затор s к ней применим; при этом в соответствии со смыслом s с i связывается
первый аргумент интерпретатора – р, а второй остается свободным параметром.)
Применяя (**), получаем
s(i,p)(d) = i(p,d) = r.
Обратите внимание, чтобы выписать результат специализатора, нужно «пере
двинуть» функциональные скобки на позицию вправо и опустить символ специа
лизатора.
Другими словами, s(i,p) – это такая программа р’, которая после применения к
данным d дает результат r. Следовательно, р’ эквивалентна программе р. Но р’ на
писана уже на языке М, а не на L! Следовательно, р’ – это перевод программы р
на язык М. Итак, связав интерпретатор (написанный на языке М) с исходной про
граммой на языке L, получили ее перевод на М.
Кратко это можно выразить так: специализация интерпретатора по програм
ме дает ее перевод.
Подумайте, что в общем случае можно сказать о качестве полученного перевода –
скорости работы, объеме памяти; а что – о скорости перевода?
Современное состояние языков программирования

Важнейшие абстракции: данные, операции, связывание
77
Специализация специализатора. Итак, при различных i специализатор дает
переводы с разных языков. Нетрудно теперь догадаться, что при фиксированном i
специализатор s представляет собой компилятор с языка L на язык М. Ведь, как
мы видели, в этом случае он по заданной р получает ее перевод р’. Действительно,
посмотрим, что такое s(s,i)? Вновь применяя (**), получаем
s(s,i)(p) = s(i,p).
Но ведь s(i,p) – это р’, перевод программы р на язык М! Так что s(s,i) (написан
ный на М) – это компилятор KLM с языка L на язык М.
Кратко выразим это так: специализация специализатора по интерпретатору
дает компилятор. Или еще короче: автоспециализация по интерпретатору дает
компилятор.
Снова есть повод подумать о возможном качестве компилятора и затратах на его
получение в общем случае.
Двойная автоспециализация. Специализатор может выступать и в роли су
перкомпилятора. Ведь по заданному интерпретатору i (который можно считать
описанием языка L) специализатор выдает компилятор с языка L на язык М. Дей
ствительно, посмотрим, что такое s(s,s)? Опять применяя (**), получаем
s(s,s)(i) = s(s,i).
Но ведь s(s,i) = KLM! Так что s(s,s) – это действительно суперкомпилятор над
языком М (в свою очередь написанный на М).
Кратко выразим это так: двойная автоспециализация дает суперкомпилятор.
Вопрос. Нельзя ли получить чтолибо интересное тройной автоспециализацией?
Подсказка. А что, если подставлять различные воплощения специализатора s?
Три последовательных применения специализатора удобно наглядно выра
зить следующей серией соотношений:
s(s,s)(i)(p)(d) = s(s,i)(p)(d) = s(i,p)(d) = i(p,d) = r.
Другими словами, s(s,s) воспринимает описание языка L (то есть i) и выдает
компилятор s(s,i), который, в свою очередь, воспринимает исходную программу р
на языке L и выдает ее перевод s(i,p), который уже воспринимает исходные дан
ные d и выдает результат r.
Таким образом, мы убедились, что абстракция связывания (точнее, частичное
связывание) позволяет с единых позиций рассмотреть важнейшие понятия тео
рии трансляции и вывести полезные закономерности. Именно связав i с р, полу
чили перевод; связав s c i, получили компилятор; связав s с s – суперкомпилятор.
Строго говоря, мы имеем здесь дело не с суперкомпилятором, а с более универсаль
ной программой.
Вопрос. В чем это проявляется?
Приведенные выше соотношения называют соотношениями ФутамурыТур
чина. Способ их изложения позаимствован у С. А. Романенко.

78
Замечание (о сущности трансляционных понятий). Хотя непосредственное прак
тическое значение соотношений ФутамурыТурчина пока проблематично, они по
могают увидеть заманчивые перспективы, а также четче выделять понятия.
Действительно, обычно отличие, например, интерпретации от компиляции форму
лируют несколько расплывчато. Говорят, что интерпретатор воспринимает исход
ную программу вместе с исходными данными и выполняет ее последовательно,
«шаг за шагом», в соответствии с операционной семантикой языка L. Операцион
ной называют семантику, выраженную через последовательность действий испол
нителя, соответствующую каждому тексту на L.
Вопрос. Можно ли иными средствами задать семантику ЯП? Предложите свои
средства.
Написание интерпретаторов на машинных или ранее реализованных языках – хо
рошо известный, естественный и для многих целей удобный способ реализации
ЯП. Для некоторых из них (Лисп, Апл, Бейсик) – единственный способ полной
реализации. Это справедливо для всех языков, в которых программа может ме
няться в процессе исполнения, – только «шаг за шагом» и можно уследить за таким
изменением.
Когда говорят о компиляции, подразумевают перевод всей программы как целого, без
учета конкретных исходных данных, с исходного языка L на объектный язык М. С кон
кретными исходными данными исполняется уже результат подобного перевода.
Такого рода содержательные различия, конечно, существенны, однако значитель
ная их часть улавливается на формальном уровне, нам теперь вполне доступном.
Ведь интерпретатор – это форма с двумя аргументами, а компилятор – с одним.
Интерпретатор – это (ограниченный) аппликатор, а компилятор – это преобразо
ватель программ (сохраняющий их смысл).
Обратите внимание: приведен пример пользы от рассмотрения языковых концеп
ций (связывания) с математической позиции.
С другой стороны, важно понимать, что формальные преобразования специализа
тора в компилятор и суперкомпилятор не отражают некоторых содержательных
аспектов этих понятий. Обычно компилятор применяют ради повышения скоро
сти работы переведенных программ по сравнению с интерпретацией. Специализа
тор же в общем случае может выдать остаточную программу, состоящую, в сущно
сти, из интерпретатора и обращения к нему. В таком случае неоткуда ждать
выигрыша в скорости. При попытках «оптимизировать» такую программу за счет
раскрытия циклов и т. п. она может стать непомерно длинной. Аналогичные сооб
ражения касаются и суперкомпилятора. Тем не менее в указанном направлении
получены обнадеживающие результаты для частных видов специализаторов [4, 5].
Не до конца улавливается приведенными соотношениями и сущность компиля
ции. Она – в переводе на другой язык, на котором может оказаться вовсе невозмож
но или очень невыгодно писать интерпретатор исходного языка L (например, это
невозможно делать на небольшой встроенной бортовой машине). А ведь в наших
соотношениях все программы (кроме р) написаны на объектном языке М. Сказан
ное не означает, что в подобных случаях непригодна математическая позиция.
Просто нужны и другие математические модели компиляции. Например, проекци
онная, где компилятор рассматривается как реализация проекции (отображения
языка L на М), а не как специализация написанного на М интерпретатора (послед
него может и не существовать).
Современное состояние языков программирования

Важнейшие абстракции: данные, операции, связывание
На этом закончим обсуждение связывания как самостоятельной абстракции.
Как видим, оно оказалось весьма емким, глубоким понятием, взаимодействую
щим со многими концепциями программирования.
79
3.5. Принцип цельности
Считая достаточно обоснованной самостоятельную ценность каждой из трех вы
деленных абстракций, продемонстрируем на их примере один весьма общий
принцип проектирования, который назовем принципом цельности. Его называют
также принципом концептуальной целостности.
Суть принципа цельности – в том, что детали проекта в идеале должны быть
следствием относительно небольшого числа базисных, ключевых решений. Дру
гими словами, в цельном проекте большинство деталей можно предсказать, зная
базисные решения. Содержательно это означает, что проект выполнен на основе
цельной концепции, единого замысла, а не представляет собой нагромождения
случайностей.
Покажем, как принцип цельности проявляется на трех уровнях рассмотрения
программного проекта, два из которых – языковые.
Первый уровень – собственно программа. Сначала несколько совсем общих
соображений. Проектирование – это сочетание абстракции и конкретизации
(принимая конкретное проектировочное решение, тем самым одновременно вво
дят абстракции нижнего уровня, предназначенные для реализации принятого ре
шения, – вспомните появление новых имен при проектировании пакета управле
ние_сетью). Цельная концепция в идеале должна воплощаться согласованными
абстракциями, а отсутствие таковой проявляется в их несогласованности.
Согласованность (абстракций) понимается как удобство их совместного ис
пользования для удовлетворения определяющих потребностей.
Возвратимся к трем выделенным абстракциям. Заметим, что иметь с ними
дело приходится независимо от того, насколько сознательно они выделяются
в технологическом цикле проектирования программ. Покажем, как принцип
цельности позволяет выработать естественные критерии качества языковых кон
структов.
Следующие ниже соображения носят весьма общий, почти философский харак
тер. Это естественно, так как рассматривается один из общих принципов «фило
софии программирования». Вместе с тем получаются вполне осязаемые крите
рии и оценки.
В соответствии с принципом технологичности (который справедлив не только
для ЯП, но и для создаваемых с их помощью программ) выделяемые абстракции
призваны обслуживать определенные технологические потребности. Проявим
критерии цельности ЯП с точки зрения потребностей пошаговой детализации.
Применяя эту технологию, следует исходить из хорошо понятной постановки
задачи. Однако в понятной постановке задачи компонент мало. Следовательно,
они содержательные, емкие, имеющие непосредственную связь с сутью решаемой

80
Современное состояние языков программирования
задачи. Но тогда и операнды у этих операций обладают теми же свойствами. И их
связывание должно опираться на средства доступа к таким емким операциям и
данным. По мере детализации операций менее емкими становятся и операнды, и
средства связывания.
Итак, в процессе пошаговой детализации свойства данных, операций и связы
вания должны на каждом шаге быть взаимно согласованными по степени детали
зации.
Упражнение. Проверьте это утверждение на нашем примере с сетями. Обратите
внимание на возможность вводить содержательные понятия, не слишком беспоко
ясь пока о возможности их реализации средствами ЯП.
Второй уровень – средства программирования. Следовательно, чтобы обеспе
чить технологические потребности пошаговой детализации, языковые конст
рукты должны обслуживать согласование указанных свойств на каждом шаге де
тализации. Мы пришли к важному критерию качества языковых конструктов:
в хорошем ЯП конструкты, обслуживающие определение и использование каж
дой из упомянутых абстракций, должны быть согласованы по степени управле
ния детализацией.
Упражнение. Приведите примеры нарушения этого требования в известных вам
ЯП.
Подсказка. В Паскале функции вырабатывают только скалярный результат – нет
прямого средства сопоставить «емкой» функции согласованную по «емкости»
структуру данных. Например, нельзя определить функцию все_связи. Уже упоми
налось отсутствие развитых средств связывания с контекстом.
Третий уровень – средства развития. Подчеркнем важный момент. Содержа
тельные абстракции на каждом шаге детализации зависят от решаемой задачи.
Как уже говорилось, для работы в конкретных прикладных областях создаются
ПОЯ. Это и есть задача, решаемая с помощью базового языка. Решать ее есте
ственно также методом пошаговой детализации (иногда его называют методом
абстрактных машин). Например, мы создали абстрактную машину, работающую
с сетью. Ее команды – наши пять операций доступа к сети. При реализации этой
машины используется (но не оформлена нами явно) машина удаления связей.
Никлаусу Вирту принадлежит глубокая мысль о том, что истинное назначение
ЯП – предоставить средства для ясного и точного определения абстрактных ма
шин. Следовательно, в базовых языках должны быть согласованы между собой и
средства развития всех трех разновидностей абстракций. Другими словами, в ЯП,
претендующем на универсальность, принцип цельности в идеале призван рабо
тать при проектировании как базиса ЯП, так и средств его развития.
Упражнение. Приведите примеры нарушения этого требования в известных вам ЯП.
Подсказка. Проще всего это сделать по отношению к связыванию – в традицион
ных ЯП этот аппарат развит слабо. Легко ли, например, на Паскале определить
ПОЯ, в котором возможно раздельно определять заголовки и тела процедур, а свя
зывать их по мере необходимости?
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
