Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Стили и методы программирования. Учебное пособие для СПО

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
Язык Рефал был создан В. Ф. Турчиным для аналитических вычислений в физике. Первоначально Турчин продумал саму идею конкретизации и представил ее в виде языка, демонстративно записанного в не слишком прямо представимой форме. Например, не было понятия детерминатива, предложения имели вид, подобный
§1.1.2 E1 + (E2 * E3)= (K E1 + E2 .)* (K E1 + E3 .)
Конкретно-синтаксическая форма языка, данная в теоретической работе Турчина (см., напр. [27
]) сразу же была изменена для удобства
представления и работы
5)
. Уже при первой реализации был продуман и проверен приведенный выше алгоритм отождествления, были выброшены иерархические комментарии в начале предложений, а вместо них появились понятия детерминатива и функции.
Дальнейшая доработка потребовала процедур ввода-вывода и механизма хранения глобальных данных, что было реализовано через стеки закопанных данных. Получившийся язык Рефал-2 длительное время был практическим стандартом Рефал-систем.
В языке Рефал-4 были сделаны две попытки расширения языка. Во­первых, как и во множестве других систем, к Рефалу были достаточно механически добавлены нарождавшиеся модные объектно­ориентированные средства. Эта попытка быстро зашла в тупик и была оставлена. Во-вторых, были определены метаоперации. Это нововведение доказало свою жизнеспособность и выжило. В языке
Рефал-5 [37
], который сейчас является фактическим стандартом6), объекты были отброшены, зато последовательно была проведена как стандартная надстройка над языком идея метакодирования. В нем получили свое окончательное оформление вложенные процедуры и дополнительные условия.
Из других существующих версий языка стоит отметить Рефал-6 и Рефал+ [10
], которые развивают одну и ту же линию. В реализации Рефал+
отошли от представления, принятого в [25
], с тем чтобы воспользоваться современными алгоритмами сборки мусора. Вместо стеков закопанных значений в этих языках предлагаются объекты, которые имеют лишь одно значение. В частности, такие объекты
Стили и методы программированияНепейвода Н.Н.
111
используются для описания графического ввода и вывода, что полностью игнорируется в стандартном Рефале. В этих версиях позволяется объявить функцию откатной и пытаться при невозможности отождествлений обработать неудачу. Но автор этих версий проигнорировал концептуальную несовместимость неудач с общей структурой управления в языке Рефал. Из находок Рефал+, помимо новой структуры данных, стоит отметить концепцию упорядочения возможных отождествлений и возможность до некоторой степени управлять этим упорядочением (правда, в языке предусмотрен лишь переход от прямого порядка к его обращению, но уже это дает в некоторых случаях большой выигрыш в выразительности).
Наиболее заметным недостатком новых версий языка Рефал
7)
явилось отсутствие различения абстрактного и конкретного синтаксиса. Можно было бы просто отказаться от фиксации оформления в определении языка и дать возможность определять синтаксические расширения и представления самим разработчикам.
Стоит заметить, что нынешний язык Рефал находится в мягком концептуальном противоречии со столь блестяще реализованной в нем же идеей динамического вычисления программ. Решение исполнять ту функциональную скобку, внутри которой нет других таких скобок, было оправдано и логично при создании Рефала, а теперь оно уже мешает эффективно использовать аппарат метапреобразований. Необходимо заметить, что Рефал созрел для настоящего представления мультииерархической структуры, что позволит языку выйти на новые классы приложений. Таким образом, в ближайшее время можно ожидать появления нового сентенциального языка, реализующего идею конкретизации. Будет просто беда, если под красивой оберткой кто­нибудь подсунет в эту область концептуально непродуманное 'прагматическое' решение. Выигрыш от прагматизма будет минимальным, временным и локальным, а потери — длительными, на порядок превосходящими аналогичные для традиционных языков, и к тому же глобальными.
Именно в языке Рефал было четко показано, как выбирать структуры данных и алгоритм работы абстрактной машины для нетрадиционных вычислений и насколько это важно. В нем впервые избавились от жесткой привязки к конкретному синтаксису. Он продемонстрировал
Стили и методы программированияНепейвода Н.Н.
112
советскому программистcкому сообществу возможность альтернативных моделей вычислений, выполнив на востоке ту же роль, что Prolog на западе. В нем впервые была реализована концепция встроенных частичных вычислений программ. Он не поддался давлению моды, и этим способствовал осознанию наличия альтернатив даже в том случае, когда подходы в принципе близки. Всего этого достаточно для признания пионерской роли этого языка.
Сравнение версий сентенциального программирования
Прежде всего, методы управления языка Prolog и языка Рефал принципиально отличаются. В Prolog'е неудача глобальна, но исправима, а в Рефале — локальна, но фатальна.
Унификация в Prolog и конкретизация в Рефале являются операциями примерно одного и того же уровня общности. Но направления унификации и конкретизации ортогональны.
Конкретизация имеет дело с выражениями, подвыражения в которых могут выделяться различными способами, и древовидная иерархическая структура сочетается с линейной структурой внутри одного уровня иерархии, а при унификации в Prolog и в логике все выражения жестко ограничены скобками либо запятыми, то есть присутствует лишь иерархическая структура. Конкретизация не заглядывает внутрь иерархии глубже, чем это явно указано в соответствующем правиле, а унификация может двигаться по уровням иерархии вглубь настолько, насколько это необходимо. При конкретизации переменные локальны, и их значения не влияют на интерпретацию остальной области памяти, а при унификации переменные глобальны, полученная в результате унификации подстановка производится сразу во всем поле зрения, а не только в его активной части. При конкретизации в ходе установления значений переменных возможны неудачи и возвраты, а при унификации значения переменных рекурсивно набираются в соответствии с алгоритмом нахождения унифицирующей подстановки, и неудача этого единственного варианта означает неудачу всей попытки
Стили и методы программированияНепейвода Н.Н.
113
унификации.
Внимание!
Модели унификации и конкретизации формально несовместимы, поскольку, соединив их, мы получаем алгоритмически неразрешимое понятие отождествления (Н. К. Косовский и др., 1990).
Это — глубочайший теоретический результат и одно из редких прямых предупреждений, сделанных теорией практике
8)
. Поэтому при сходстве многих идей, положенных в их основу, эти модели развиваются и должны дальше развиваться независимо (что не исключает творческого заимствования идей из одной ипостаси подхода в другую). Обратите внимание, что мы столкнулись с той же самой ситуацией, которая имеет место для циклической и рекурсивной ипостасей структурного программирования.
Точно так же, как циклическая ипостась структурного программирования, Рефал приспособлен для работы с данными, развернутыми в основном вширь и для развертывания процесса в ширину. Точно так же, как рекурсивная ипостась, Prolog приспособлен для развертывания процесса в глубину и для работы с данными, имеющими ограниченную ширину, но зато большую глубину.
Даже машинная реализация этих языков сродни двум ипостасям структурного программирования. В Рефале вызовы, которые выглядят
как рекурсивные, на самом деле рекурсией не являются
9)
, поскольку мы заканчиваем породивший вызов, и лишь после этого переходим к отработке порожденных. Prolog больше похож на рекурсию, поскольку после вызова внутреннего предиката мы можем возвратиться к внешнему и продолжить попытки его унификации. В Рефале достаточно общего поля памяти, а в Prolog вынуждены запоминать также
управляющие данные ( точки возврата
10)
).
Стоит заметить, что сентенциальное программирование, и особенно его разновидность, базирующаяся на модели отождествления-замены, великолепно сочетается с идеей ассоциативной памяти (см. стр. 31), и здесь возможен прорыв одновременно на аппаратном и программном уровнях.
Стили и методы программированияНепейвода Н.Н.
114
Вариант сентенциального программирования, базирующийся на возвратах и унификации, отлично сочетается с идеей машины потоков данных. Японцы попытались использовать его в своем проекте ЭВМ пятого поколения. Провал данного проекта надолго дискредитировал направление соединения сентенциального программирования с потоками данных, но к нему придется вернуться в будущем на другой технической и, видимо, на гораздо более концептуально выверенной программистской основе.
Концепция унификации и возвратов после неудач исключительно хорошо подходит для выражения -параллелизма (см. § 15.2). Более того, уже имеются системы (в частности, Muse), реализующие этот вариант параллелизма в языке Prolog.
Рефал, в свою очередь, великолепно подходит для &-параллелизма. Подстановки значений переменных в результирующее выражение можно осуществлять независимо друг от друга. Более того, в принципе можно было бы даже в нынешнем варианте Рефала вычислять различные функциональные скобки в параллель, помешать этому могут лишь значения, передаваемые через аппарат закапывания­выкапывания. Но это — стандартная проблема синхронизации для параллельных вычислений, с которой можно справляться хорошо разработанными средствами, тем более что аппарат для соответствующей разметки программы еще в ходе ее составления концептуально подготовлен в языке.
Таким образом, две ветви сентенциального программирования ориентированы даже на разные классы параллельных вычислений. Именно на примере сентенциального программирования нами был сделан вывод о том, что и для других стилей должны быть альтернативные реализации. Их выявлению мешал прежде всего закон экологической ниши.
При создании и развитии языков PROLOG и Рефал ярко проявились сильные и слабые стороны русской и англо-американской школ науки.
В. Ф. Турчин проделал адекватный анализ, не устаревший за 40 лет, но он не стремился к общепонятности и слишком большой популяризации (может быть, потому, что ему не нужно было выбивать гранты). Его последователи четко восприняли идею и развивали ее, практически
Стили и методы программированияНепейвода Н.Н.
115
полностью избегая концептуально противоречащих ей возможностей. Но популяризация языка и внешняя сторона работы с ним (удобные системы, интерфейсы и т. п.) оказались практически полностью проигнорированными, и поэтому язык остается достоянием узкой группы приверженцев.
Сами представители Рефал-сообщества объясняли свою позицию относительно интерфейсов примерно следующим образом.
— Чайники и ламеры все равно Рефалом не пользуются, а квалифицированный человек сам легко напишет переходник, тем более, что код системы открыт.
Автор в свое время вынужден был писать переходник между Рефалом-2 и Алголом 68, но, конечно же, такое решение и приведенная выше аргументация неудовлетворительны.
Создатели Prolog с самого начала в значительной мере использовали теорию и методологию как заклинания либо молитвы, не имеющие отношения к сути дела и произносимые для его освящения. Тем самым теоретическая база сразу же оказалась неадекватной, что и привело к быстрому расползанию системы и потере концептуального единства. Язык в значительно большей мере, чем Рефал, оказался загрязнен
чужеродными элементами
11)
.
Неадекватность теории практике помешала осознанию реальных достижений подхода, основанного на унификации, поскольку они часто противоречили мифам и саморекламе. Зато развитие внешнего оформления и удобных (с точки зрения дизайна) средств работы с языком шло адекватными темпами, а реклама его действительных и мнимых достижений далеко опережающими. Язык вошел в практику обучения многих университетов мира и попал даже в стандарты программ обучения специалистов IFAC.
Если говорить о практических задачах, то Prolog значительно лучше подходит для поиска, а Рефал — для синтаксических преобразований. Стоит также помнить, что в нынешнем состоянии Prolog не может служить даже для прототипирования, это язык лишь для моделирования решений и логики поведения программы.Но это — особенность нынешних конкретных реализаций идеи унификации и возвратов, она
Стили и методы программированияНепейвода Н.Н.
116
связана с тем, что примитивный концептуальный механизм пришел в противоречие с выявившимися богатейшими потенциальными возможностями подхода.
Рефал делает символьные преобразования столь же эффективно, как и программа на традиционном языке, и поэтому может быть использован на всех уровнях: и для создания прототипа программы, и для написания надпрограммы, и для написания подпрограммы.
Таким образом, Рефал по эффективности и ясности представления уже сейчас может служить языком прототипирования, и, если бы его снабдить удовлетворительными интерфейсами, вполне мог бы служить и для окончательных решений, работающих в многоязыковой среде. В момент написания книги существует единственный имеющийся надежно работающий интерфейс Рефала: с языком PHP преобразования HTML-текстов.
В особенности Рефал хорош в тех случаях, когда нужно произвести нетривиальное преобразование символьных входных либо выходных файлов. Его использование, как показала практика автора и студентов в многоязыковом программировании, зачастую оправдывается даже тогда, когда ведется передача данных через файл.
У Prolog ныне интерфейсы имеются, но они, как правило, ориентированы лишь на C++ и LISP
12)
и совершенно не
стандартизованы. Каждая реализация имеет свой интерфейс.
Мы затронули общий недостаток нынешних систем сентенциального программирования. Это — плохая проработка связей с другими языками. При создании средств высших уровней необходимо с самого начала продумать вопросы связи с другими языками и использования языка в многоязыковой и многостилевой методологии программирования.
1)
Они не имели никаких сведений о Рефале и работали совершенно независимо. Просто потребность сентенциального программирования назрела. К счастью для информатики, обе группы инициаторов не были осведомлены о работах друг друга, иначе, скорее всего, одна из двух ортогональных концепций осталась бы неразвитой. Это подтверждает история других стилей: тот, кто первым добился успеха, захватывает
Стили и методы программированияНепейвода Н.Н.
117
экологическую нишу и видоизменяет условия в ней таким образом, чтобы ничто другое не могло в ней выжить (причем часто нет никакого злого умысла, просто работают законы развития науки и вообще эволюционирующих систем).
2)
Как именно это делается, сейчас неважно.
3)
Одновременно данное направление нанесло и существенный вред этой теории и методологии, который был бы еще глубже, если бы у Prolog'а с самого начала не было бы друга-соперника Рефала.
4)
Слишком прямое применение теории, особенно когда получается привлекательное на вид следствие — бич современной науки. Именно оно приводит к тому, что многие серьезные практики попросту игнорируют теорию, из-за этого делают другие, не менее глупые и вредные, и не менее привлекательные на вид, ошибки. Пример такой глобальной ошибки — С++, лишь обостривший все проблемы традиционного программирования. Он создавался практиками, по их же собственному признанию, принципиально игнорировавшими теории.
5)
Если человек не привязан к конкретным словам, то обычно это доказывает, что он ясно осознал идеи, которые отстаивает.
6)
Внимание! В самых последних реализациях, называемых PZ SciTE, язык без огласки чуть-чуть пересмотрен, и отражено это лишь в файлах news.txt.
7)
Подавляющее большинство систем программирования имеют этот недостаток, но в данном случае он ощущается наиболее остро.
8)
Даже прямые предупреждения, как правило, игнорируются практиками, многие из которых не понимают самого понятия алгоритмической неразрешимости; в качестве примера можно взять безвременно скончавшийся Рефал-6.
9)
Примером того, насколько многие привыкли судить о явлениях по внешнему виду, а не по сущности, является кочующее из книги в книгу утверждение о том, что Рефал — язык функционального рекурсивного программирования.
10)
После этой аналогии становится более ясно, почему программисты трактуют использование отсечения ! в языке PROLOG как хакерство. Представьте себе, что было бы, если бы Вам в C++ предоставили явный доступ к отложенным из-за рекурсии вызовам процедур и разрешили по своему произволу их убирать!
11)
История отказа от введения объектов в Рефал является практически
Стили и методы программированияНепейвода Н.Н.
118
исключительным в мире современной информатики примером понимания вреда концептуальных противоречий. В конце концов, разум должен стоять выше моды!
12)
Некоторые коммерческие системы Prolog имеют интерфейсы еще и с
Java.
Стили и методы программированияНепейвода Н.Н.
119
Функциональное программирование
Теоретические предпосылки. Списки и простейшие операции. Значения и модель вычислений. Динамическое порождение программ и функционалы. Объекты и синтез программ.
Функциональное программирование объясняется на примере диалекта Common Lisp языка LISP. Этот диалект наиболее распространен и имеет официальный стандарт. Common Lisp может работать не только в пакетном режиме (когда он запускается как обычная программа), но и в режиме диалога.
LISP — вероятно, первый из практически реализованных языков
1)
, который основывался на серьезном теоретическом фундаменте и пытался поднять практику программирования до уровня концепций, а не наоборот — опустить концепции до уровня существовавшей на момент создания языка практики.
В настоящий момент функциональное программирование представлено целым семейством языков, но LISP свои позиции не сдает.
Лямбда-абстракции
В некоторых случаях осознанное усвоение концепций даже на самом низком уровне нереально без базовых теоретических сведений. А знакомство с таким базисом, в свою очередь, стимулирует значительно более глубокий интерес к теории и способствует пониманию того, что на высшие уровни знаний и умений не подняться без овладения теорией.
Теоретической основой языка LISP является логика функциональности: комбинаторная логика или (по наименованию одного из основных понятий в наиболее популярной из нынешних ее формализаций) ­исчисление.
В -исчислении выразительные средства, на первый взгляд, крайне скупы. Имеются две базисные операции: применение функции к аргументу (fx) и квантор образования функции по выражению
Стили и методы программированияНепейвода Н.Н.
120