- •У.Клоксин, к.Меллиш программирование на языке пролог Для программистов и пользователей эвм. Предисловие редакторов перевода
 - •Предисловие ко второму изданию
 - •Предисловие к первому изданию
 - •Глава 1 введение
 - •1.1. Факты
 - •1.2. Вопросы
 - •1.3. Переменные
 - •1.4. Конъюнкции
 - •1.5. Правила
 - •1.6. Заключение и упражнения
 - •Глава 2 более детальное описание
 - •2.1. Синтаксические правила
 - •2.1.1. Константы
 - •2.1.2. Переменные
 - •2.1.3. Структуры
 - •2.2. Литеры
 - •2.3. Операторы
 - •2.4. Равенство и установление соответствия
 - •2.5. Арифметика
 - •2.6. Общая схема согласования целевых утверждений
 - •2.6.1. Успешное доказательство конъюнкции целевых утверждений
 - •2.6.2. Рассмотрение целевых утверждений при использовании механизма возврата
 - •2.6.3. Установление соответствия
 - •Глава 3. Использование структур данных
 - •3.1. Структуры и деревья
 - •3.2. Списки
 - •3.3. Принадлежность элементов списку
 - •3.4. Пример: преобразование предложений
 - •3.5. Пример: упорядочение по алфавиту
 - •3.6. Использование предиката присоединить и спецификация деталей
 - •Глава 4. Возврат и отсечение
 - •4.1. Порождение множественных решений
 - •4.2. Отсечение
 - •4.3. Общие случаи использования отсечения
 - •4.3.1. Подтверждение правильности выбора правила
 - •4.3.2. Комбинация «отсечение-fail»
 - •4.4. Проблемы, связанные с использованием отсечения
 - •Глава 5 ввод и вывод
 - •5.1. Ввод и вывод термов
 - •5.1.1. Вывод термов
 - •5.1.2. Ввод термов
 - •5.2. Ввод и вывод литер
 - •5.2.1. Вывод литер
 - •5.2.2. Ввод литер
 - •5.3. Ввод предложений
 - •5.4. Чтение файлов и запись в файлы
 - •5.4.1. Запись в файлы
 - •5.4.2. Чтение файлов
 - •5.4.3. Ввод программ
 - •5.5. Объявление операторов
 - •Глава 6. Встроенные предикаты
 - •6.1. Ввод новых утверждений
 - •Списковая форма записи
 - •6.2. Выполнение и невыполнение целевого утверждения
 - •6.3. Классификация термов
 - •6.4. Работа с утверждениями как с термами
 - •6.5. Создание структур и работа с компонентами структур
 - •6.6. Воздействие на процесс возврата
 - •Отсечение
 - •6.7. Формирование составных целевых утверждений
 - •Конъюнкция целей
 - •Дизъюнкция целей
 - •6.8. Равенство
 - •6.9. Ввод и вывод данных
 - •6.10. Обработка файлов
 - •6.11. Вычисление арифметических выражений
 - •6.12. Сравнение чисел
 - •6.13. Наблюдение за выполнением программы на Прологе
 - •Глава 7. Еще несколько примеров программ
 - •7.1. Словарь в виде упорядоченного дерева
 - •7.2. Поиск в лабиринте
 - •7.3. Ханойские башни
 - •7.4. Справочник комплектующих деталей
 - •7.5. Обработка списков
 - •7.6. Представление и обработка множеств
 - •7.7. Сортировка
 - •7.8. Использование базы данных: random, генатом, найтивсе
 - •Генератор случайных чисел (random)
 - •Генератор имен (генатом)
 - •Генератор списков структур (найтивсе)
 - •7.9. Поиск по графу
 - •7.10. Просеивай Двойки, Просеивай Тройки
 - •7.11. Символьное дифференцирование
 - •7.12. Отображение структур и преобразование деревьев
 - •7.13. Применение предикатов clause и retract
 - •Глава 8. Отладка пролог-программ
 - •8.1. Расположение текстов программ
 - •8.2. Типичные ошибки
 - •8.3. Модель трассировки
 - •8.4. Трассировка и контрольные точки
 - •Выдача информации о цели
 - •Выдача информации о предшественниках
 - •Изменение уровня трассировки
 - •Вмешательство в процесс согласования цели
 - •Другие команды
 - •Заключение
 - •8.5. Фиксация ошибок
 - •Глава 9. Использование грамматических правил в прологе
 - •9.1. Проблема синтаксического анализа
 - •9.2. Описание синтаксического анализа на языке Пролог
 - •9.3. Запись грамматических правил в Прологе
 - •9.4. Присоединение дополнительных аргументов
 - •9.5. Введение дополнительных условий
 - •9.6. Заключение
 - •Глава 10. Пролог и математическая логика
 - •10.1. Краткое введение в исчисление предикатов
 - •10.2. Приведение формул к стандартной форме
 - •Этап 1 - исключение импликаций и зквивалентностей
 - •Этап 2 - перенос отрицания внутрь формулы
 - •Этап 3 - сколемизация
 - •Этап 4 - вынесение кванторов общности в начало формулы
 - •Этап 5 - использование дистрибутивных законов для & и #
 - •Этап 6 - выделение множества дизъюнктов
 - •10.3. Форма записи дизъюнктов
 - •10.4. Принцип резолюций и доказательство теорем
 - •10.5. Хорновские дизъюнкты
 - •10.6. Пролог
 - •10.7. Пролог и логическое программирование
 - •Глава 11. Программные проекты на прологе
 - •11.1. Простые проекты
 - •11.2. Более сложные проекты
 - •Приложение а. Ответы к некоторым упражнениям
 - •Приложение в. Программа приведения формул исчисления предикатов к стандартной форме
 - •Этап 1 - исключение импликаций
 - •Этап 2 - перенос отрицания внутрь формулы
 - •Этап 3 - сколемизация
 - •Этап 4 - вынесение кванторов общности в начало формулы
 - •Этап 5 - использование дистрибутивных законов для. & и #
 - •Этап 6 - выделение множества дизъюнктов
 - •Печать утверждений
 - •Приложение с. Различные версии языка пролог
 - •Синтаксис
 - •Различные ограничения
 - •Возможности окружения
 - •Компиляция
 - •Специальные встроенные предикаты
 - •Средства отладки
 - •Приложение d. Пролог для эвм dec system-10
 - •Пример сеанса работы
 - •Синтаксис
 - •Различные ограничения
 - •Возможности окружения
 - •Компиляция
 - •Различия во встроенных предикатах
 - •Дополнительные встроенные предикаты
 - •Средства отладки
 - •Литература
 - •Приложение е. Микро-пролог
 - •Пример сеанса работы
 - •Синтаксис
 - •Различные ограничения
 - •Возможности окружения
 - •Специальные встроенные предикаты
 - •Средства отладки
 - •Литература
 - •Приложение f. Система мпролог[19]
 - •Пример сеанса работы
 - •Синтаксис
 - •Модульность
 - •Компоненты системы мПролог
 - •Различные ограничения
 - •Дополнительные встроенные предикаты
 - •Средства отладки
 - •Литература
 - •Примечания
 
10.7. Пролог и логическое программирование
В нескольких последних разделах было показано, как используются в Прологе идеи доказательства теорем. Можно видеть, что наши программы довольно похожи на гипотезы о проблемной области, а вопросы очень похожи на теоремы, которые нам хотелось бы доказать. Таким образом, программирование на Прологе имеет мало общего с процессом выдачи машине указаний о том, что и когда следует делать. Оно скорее состоит в передаче машине информации, которая предполагается истинной, и обращении к ней с вопросами о возможных следствиях из этой информации. Идея о том, что программирование должно выглядеть именно так, привлекательна и она привела многих специалистов к исследованию концепции логического программирования, то есть программирования на языке логики, как практической альтернативы обычному. Такой подход резко отличается от использования традиционных языков программирования подобных Фортрану или Лиспу, при программировании на которых необходимо как можно более подробно описать что и когда должна делать вычислительная машина. Преимущества логического программирования должны проявиться в том, что программы станут более понятными. Они не будут содержать затрудняющие понимание детали относительно того как решать задачу, а скорее будут напоминать описание того, что собой представляет результат решения. Кроме этого, если программа выглядит как описание (спецификация) того, что предполагается получить, то и относительно проще проверить (вручную или, возможно, используя какие-то автоматические средства), делает ли она в действительности то, что требуется. Подводя итог, можно сказать: преимущества языка логического программирования были бы следствием того, что программы обладают как декларативной семантикой, так и процедурной. Мы бы знали что программа вычисляет, а не как она это делает. Мы не будем здесь рассматривать логическое программирование вообще. Интересующемуся этим вопросом читателю рекомендуем обратиться к книге Ко-walski R. Logic for Problem Solving, North Holland, 1979.
Давайте рассмотрим Пролог как кандидата на место языка логического программирования и посмотрим, насколько хорошо он для этого подходит. Прежде всего, ясно, что некоторые программы на Прологе действительно представляют описание проблемной области на языке логики. Запись:
мать(Х,Y):- родитель(Х,Y), женщина(Y).
можно рассматривать как описание того, что значит быть матерью (это значит быть женщиной и быть одним из родителей). Это утверждение выражает высказывание, которое, как мы предполагаем, должно быть истинным, и, кроме того, указывает, как показать, что кто-то является матерью. Аналогично, утверждения;
присоединить([], X, X).
присоединить([А|В],С[А|D]):- присоединить (B,C,D).
говорят о том, что собой представляет добавление одного списка в начало другого списка. Если пустой список помещается в начало некоторого списка X, то результатом будет X. С другой стороны, если непустой список присоединяется в начало некоторого списка, то головой списка-результата будет голова присоединяемого списка. Кроме того, хвостом списка-результата будет список, получаемый в результате присоединения хвоста первого списка ко второму списку. Можно считать, что эти утверждения описывают отношение присоединить, так же как и (возможно) то, как в действительности присоединить один список к другому.
Это все верно лишь для некоторых программ на Прологе. А какое возможное логическое значение можно приписать утверждениям подобным следующим?
memberl(X, List):- var(List),!,fail.
memberl(X,[X|_]).
memberl(X,[_|List]):- memberl(X,List).
print(0):-!.
print(N):- write(N), N1 is N-1, print(N1).
noun(N):- name(N,Name1), append(Name2, [ll5],Namel), name(RootN,Name2), noun(RootN).
implies(Assum,Concl):-asserta(Assum), call(Concl), retract(Concl).
Эта проблема имеет место для всех «встроенных» предикатов, используемых в программах на Прологе. Предикат подобный Var(List) ничего не говорит о принадлежности элемента списку, а проверяет состояние переменной (является ли указанная переменная неконкретизированной), возникающее в процессе доказательства. Аналогично, «отсечение» говорит кое-что о доказательстве высказывания (выбор каких альтернатив можно игнорировать), а не о самом этом высказывании. Два указанных «предиката» можно рассматривать как способ выражения управляющей информации о том, как должно выполняться доказательство. Точно так же, предикаты подобные write(N) не имеют каких-либо интересных логических свойств, но заранее предполагают, что в ходе доказательства будет достигнуто определенное состояние (N конкретизируется) и начинают обмен информацией с программистом, сидящим за терминалом. Целевое утверждениеname(N, Name1) говорит кое-что о внутренней структуре объекта, который в исчислении предикатов был бы неделимым символом. В Прологе можно преобразовывать символы в строки литер, структуры в списки и в утверждения. Эти операции нарушают замкнутость высказываний исчисления предикатов. В последнем примере, использование предиката asserta означает, что правило, о котором идет речь, добавляет что-то к множеству аксиом. В логике каждое правило или факт сохраняет истинность независимо от того, существуют ли какие либо другие факты или правила. В данном случае мы имеем дело с правилом, которое грубо нарушает этот принцип. Кроме того, если мы используем это правило, то окажемся в ситуации, когда на разных этапах доказательства имеется различное множество аксиом. Наконец, то что в одном из правил предполагается использовать терм Concl в качестве целевого утверждения, означает, что допускается, чтобы переменная обозначала высказывание, встречающееся в некоторой аксиоме. Такая конструкция не относится к числу тех, которые могут быть выражены на языке исчисления предикатов, но напоминает возможности, которые могут быть представлены логикой более высокого порядка.
На приведенном примере можно видеть, что некоторые программы на Прологе, можно понять лишь в терминах, описывающих что и когда может произойти при выполнении программ и каким образом программы сообщают системе о том, что нужно делать. В качестве крайнего случая, можно привести программу для генатом представленную в гл. 7. Вряд ли вообще может быть дана какая-либо декларативная интерпретация этой программы. Имеет ли тогда смысл рассматривать Пролог как язык логического программирования? Можем ли мы реально надеяться на какие-то преимущества логического программирования применительно к нашим программам на Прологе? На оба этих вопроса можно дать положительный ответ и основанием для этого служит то, что приняв соответствующий стиль программирования, мы все же можем получить некоторые преимущества благодаря связи Пролога с логикой. Ключевым моментом является использование разбиения программ на части, ограничивающие использование нелогических операций небольшим множеством утверждений. В качестве примера в гл. 4 было показано, как в некоторых случаях «отсечение» может быть заменено предикатом not. В результате таких замен, программу, содержавшую целый ряд «отсечений» можно свести к программе, в которой «отсечение» используется лишь однажды (в определении not). Использование предиката not даже если он не совсем точно соответствует логическому '~' позволяет восстановить часть логической основы программы. Аналогично, ограничивая область применения предикатов asserta и retract определениями небольшого числа предикатов (таких как генатом инайтивсе), можно добиться того, что в целом программа становится более понятной по сравнению с программой, в которой эти предикаты свободно используются где угодно.
Таким образом, с появлением Пролога конечная цель, состоящая в создании языка логического программирования, не была достигнута. Тем не менее, Пролог дал практическую систему программирования, обладающую в некоторой степени свойствами, которыми должен обладать язык логического программирования – ясностью и декларативностью. Между тем ведутся работы по разработке улучшенных версий Пролога, которые более близки к логике чем имеющиеся в настоящее время. К числу наиболее важных работ в этой области относятся работы по созданию практической системы программирования, в которой нет необходимости использовать «отсечение» и которая имеет вариант предиката not точно соответствующий логическому понятию отрицания.
