Author: Малпас Дж.
Tags: вычислительная математика численный анализ математика программирование информатика языки программирования компьютерные технологии язык программирования пролог
ISBN: 5-02-014509-2
Year: 1990
ДЖ. МАЛПАС
РЕЛЯЦИОННЫЙ
ЯЗЫК
ПРОЛОГ
И ЕГО ПРИМЕНЕНИЕ
Перевод с английского
А.А. ТИТОВА
Под редакцией
В.Н. СОБОЛЕВА
МОСКВА "НАУКА"
ГЛАВНАЯ РЕДАКЦИЯ
ФИЗИКО-МАТЕМАТИЧЕСКОЙ ЛИТЕРАТУРЫ
1990
ББК 22.18
М19
УДК 519.682
Prolog:
A Relational Language
and Its Applications
John Malpas
Prentice-Hall International,
Inc.
M а л п а с Дж. Реляционный язык Пролог и его применение: Пер. с
англ. /Под редакцией В.Н. Соболева. - М.: Наука. Гл..ред. физ.-мат. лит.,
1990. - 464 с. ISBN 5-02-014509-2.
Описывается реляционный язык программирования Пролог, рассматривается
методика программирования и конкретные приложения. Содержит большое число
удачно подобранных примеров, иллюстрируюишх суть обсуждаемых явлений, подроб-
подробный предметный указатель, глоссарий.
Для специалистов в области вычислительной техники и информатики.
Табл. 23. Ил. 42. Библиогр. 117 иаэв.
1404000000-120
ISBN 5-02-014509-2
1987 by Prentice-Hall, Inc.
A Division of Simon & Schuster
Englewood CUffs, NJ 07632
"Наука". Фюматлит, перевод
иа русский язык, 1990
ОГЛАВЛЕНИЕ
Предислоиие редактора перевода 6
Предислоиие 8
Введение 13
Глава 0. Логика, логическое программирование и Пролог 17
0.1. Знакомство с логическим программированием "
0.2. Традиционная логика 19
0.3. Начальный период развития формальной логики 24
0.4. Логика высказываний 29
0.5 Логика предикатов .- 37
0.6. От формальной логики — к логическому программированию. . „ . . . 50
0.7. Развитие языка Пролог 59
0.8. Синтаксис языка Пролог 62
¦ 0.9. Фразы Хорна как средство представления знаний 64
0.10. Семантика Пролога 66
0.11. Метаязык / объектный язык 68
0.12. Сферы применения языка Пролог 72
Библиографические заметки 73
Глава 1. Факты и правила 75
1.1. Использование языка Пролог 75
1.2. Факты 76
1.3. Запросы к базе данных 78
1.4. Правила 82
1.5. Процедуры 87
1.6. Рекурсивные процедуры 90
1.7. Типы отношений 95
Библиографические заметки 101
Упражнения 102
Глава 2. Арифметика и структуры данных 105
2.1. Арифметика 105
2.2. Структуры данных 107
2.3. Списки ПО
1*
4 ОГЛАВЛЕНИЕ
2.4. Процедуры, выполняющие действия со списками 114
2.5. Способы представления базы данных 120
Библиографические заметки 126
Упражнения , 126
Глава 3. Управление ходом выполнения программы 129
3.1 Как выполняется запрос в Прологе 129
3.2. Предикат "сократить" 141
3.3. Отрицание как неудача запроса 150
3.4. Встроенные предикаты, предназначенные для обеспечения воода-
вывода 154
3.5. Встроенные предикаты, предназначенные для управления файлами 156
3.6. Проверка типа герма 157
3.7. Действия с текущей программой 159
3.8. Компараторы 164
3.9. Прочие встроенные предикаты ¦ 164
3.10. Операции 168
3.11. Преобразование процедурного алгоритма в программу на языке
Пролог. ¦. ... 171
Библиографические заметки - 174
Упражнения • 175
Глава 4. Подходы к программированию на нзыке Пролог 178
Введение 178
4.1. Реляционный подход 180
4.2. Взгляд на программу с точки зрения потока данных 190
4.3. Бихевиористичсский подход 200
Библиографические заметки 203
Упражнения 203
Глава 5. Обработка текста 206
Введение 206
5.1. Лексический анализатор 207
5.2. Система нисходящего грамматического разбора , 211
5.3. Система восходящего грамматического разбора 217
5.4. Конвертер программ с DEC-10 Пролога на микро-Пролог 229
5.5. Язык запросов 237
Библиографические заметки 250
Упражнения 250
Глава 6. Представление знаний 252
6.1. Представление знаний при помощи Пролога 252
6.2. Семантические сети 262
6.3. Фреймы 264
6.4. Объектно-ориентированное программирование 268
6.5. Механизм наследования в Прологе 271
6.6. Программа, выполняющая запросы к базе данных 282
6.7 Описание изменении базь( данных 291
Библиографические заметки , 298
Упражнения 299
ОГЛАВЛЕНИЕ 5
Глава 7. Экспертные консультации . 302
7.1. Системы экспертных консультаций 302
7.2. Запоминание пути вывода ^ 305
7.3. Видимый Пролог 310
7.4. Интерпретатор, обнаруживающий циклы 314
7.5. Заключение: стиль программирования на Прологе 318
Библиографические заметки 326
Упражнения 326
Приложения 328
I. Основная терминология 328
II. Полезные программы 333
Различные процедуры C33). Процедуры сбора множества ответов
C33). Процедуры ввода-вывода низкого уровня C34). Программа
"отобразить _ состояние" C35). Экранно-ориентированиая програм-
программа, предназначенная для выполнения запросов к базе данных C36).
III. Показательный пример. Программа планирования работы завода 339
IV. Версии языка Пролог 381
СиПролог C81). Квинтус Пролог C88).Система программирования
на Прологе фирмы Сайлоджик C93).Пролог-2D00). Эрити Пролог
D07). УНСВ Пролог D12). Турбо Пролог D17).
V. Ответы к упражнениям 426
ополиеиие
441
1. Встроенные предикаты, предназначенные для работы с окнами .... 441
2. Перечень встроенных предикатов, предназначенных для работы
с графическим интерфейсом фирмы Борланд (BGI) ........... 444
писок литературы 448
редметный указатель 459
ПРЕДИСЛОВИЕ РЕДАКТОРА ПЕРЕВОДА
Вниманию читателя предлагается книга, посвященная современному
языку программирования наивысшего уровня, широко используемому при
решении многих актуальных проблем и оспаривающему в настоящее вре-
время право считаться основным языком вычислительных систем пятого поко-
поколения. Пролог представляет сейчас единственную приемлемую альтерна-
альтернативу Лиспу в качестве языкового средства при разработке систем искус-
искусственного интеллекта.
Название языка составлено из начальных частей двух слов: Програм-
Программирование ЛОГическое. Пролог освобождает пользователей от необхо-
необходимости обдумывания правил вычисления значений и планирования дей-
действий, реализуемых в процессе выполнения программы, позволяя сосре-
сосредоточить внимание на логической спецификации, описывающей решаемую
задачу. Этот язык обеспечивает относительно простое осуществление со-
сопоставления заданных объектов с эталонами. Он принципиально отличает-
отличается от общепризнанных процедурных языков (Си, Паскаль, Модула-2, Ада,
Фортран) и функционального языка Лисп. Программирование на нем
носит несколько необычный характер. Пролог-программа представляет
собой совокупность дескриптивных определений набора отношений с
включением императивных компонентов. Она больше является описанием
того, что нужно вычислить, чем того, как надо это сделать. Выполнение Про-
Пролог-программы заключается в использовании логических определений
отношений (заданных в программе) для вычисления конкретных приме-
примеров этих отношений.
Несмотря на перспективность и высокие достоинства Пролога, он поч-
почти не нашел отражения в отечественной научно-технической литературе,
что существенно сдерживает наших исследователей и разработчиков. Сча-
стлиным исключением является переводная книга К. Кларка, Ф. Маккей-
ба и др. "Введение в логическое программирование на микро-Прологе",
вышедшая в издательстве "Радио и связь" в 1987 году. Однако ее нельзя
считать вводным курсом в Пролог, она посвящена его единственной вер-
версии со специфическим синтаксисом и представляет собой сборник статей
ПРЕДИСЛОВИЕ РЕДАКТОРА ПЕРЕВОДА 7
но практическому применению микро-Пролога, написанных разными ав-
авторами.
Данная книга весьма полно описывает язтк и методологию его при-
применения. Она позволяет включиться в его изучение неподготовленному
читателю и подняться до уровня практического программирования на
Прологе. В ней достаточно полно отражена связь описываемого языка
с логикой. Книга хорошо структурирована. В нее включено большое коли-
количество удачно подобранных примеров, иллюстрирующих суть обсуждае-
обсуждаемых явлений. Стиль изложения характеризуется четкостью и доступно-
доступностью для понимания широкой аудитории читателей. Подробный предмет-
предметный указатель, глоссарий и многочисленные подзаголовки позволяют ис-
использовать данную книгу не только как учебник, но и как справочник. В
приложении представлен обзор основных версий языка, что помогает сори-
сориентироваться в его возможностях и разнообразных реализациях.
В процессе работы на переводом мы старались наиболее точно отразить
мысли автора. Чтобы программы и примеры были понятны читателю, не
владеющему английским языком, почти все осмысленные идентификато-
идентификаторы заменены русскими эквивалентами. Неизменными остались лиль имена
встроенных предикатов.
Надеемся, что данная книга окажет существенную помощь тем, кто
занимается проблемами искусственного интеллекта, реляционными база-
базами данных, разработкой программного обеспечения, системами разбора
естественного языка, представлениями знаний, экспертными системами.
В.Н. Соболев
ПРЕДИСЛОВИЕ
Круг читателей, для которого предназначена данная
Настоящая кшаа рассчитана на нрограммисюв, владеющих по меньшей
мере одним языком прО1раммирования и интересующихся следующими
вопросами:
1) языком Пролог;
2) логическим программироранисм; " №
3) сферами применения искусственного интеллекта. '|
Знании, которые получат читатеш после изучения данной книги ' j
После изучения этой книги (н выполнения упражнений!) чтателц-
должны приобрести навыки в формулировании задач на языке Ilpojioifc*
и в программировании на Прологе для технических областей применения^
Эти знания в определенной мере могут пригодиться и при работе с иными |
вычислительными формализмами, используемыми в настоящее время1
в науке об искусственном интеллекте. На протяжении всей книги автор!,
пытается проиллюстрировать с помощью практических примеров программ
некоторые интересные аспекты теории логического программирования
и тем самым продемонстрировать пользу теории для практики. Читателям, -
более углубленно интересующимся теорией, рекомендуем обратиться к
спискам литературы в конце каждой главы.
Изучайте эту книгу, имея свободный доступ к компьютеру
Для получения максимальной отдачи от изучения данной книги же-.5
лательно. чтобы у читателей был свободный доступ к- ЭВМ с одной из ;
версий языка Пролог. Это даст возможность поэкспериментировать с каж-
каждым новым понятием, излагаемым в книге. Настоящая книга призвана
прежде всего -создать у читателя представление о том, как работает Пролог,
и о назначении этого языка. Возможно (но сложно) изучить Пролог по
данной книге и без компьютера.
В нескольких местах книги отмечаются аналогии с языком програм-
программирования Си. Эти аналогии просты и должны быть понятны даже тем
читателям, которые не знают языка Си. ;
ПРЕДИСЛОВИЕ
Темы, освещаемые в книге
В гл. О вводятся основные теоретические "понятия формальной логики,
логического программирования й языка Пролог. В разд. 0.2—0.6 расска-
рассказывается об истории развития формальной логики и в заключение обсуж-
обсуждается доказательство теорем методом резолюции в том виде, как это
применимо в Прологе. В этих разделах несведущий в данных вопросах
читатель ознакомится с богатым наследием логики, от которой и проис-
происходит язык Пролог. Здесь в контексте формальной логики вводятся мно-
многие понятия (такие как аксиома или теория), которые затем используются
в контексте языка Пролог. Понимание этих концепций читателем должно
стать более глубоким при рассмотрении их более чем в одном контексте.
Изучение гл. 0 не является строго необходимым для понимания «стальной
части книги, а для программирования на языке Пролог не требуется нали-
наличия каких-либо знаний о формальной логике. Поэтому читательГжелаюший
изучить практические аспекты языка Пролог, может при первом чтении
пропустить гл. 0.
Изучение языка
Читатель, не знающий Пролога, сможет изучить этот язык по материалу
гл. 1, 2 и 3. В гл. 1 рассказывается о фактах, правилах и запросах. В ней
вводится классификация типов отношений, существующих в окружаю-
окружающем мире, и показывается, как эти отношения могут быть представлены
с помощью языка Пролог. В гл. 2 рассматриваются арифметика, структуры
данных и обработка списков. Она заканчивается обзором способов пред-
представления базы данных. Глава 3 начинается с широкого обсуждения модели
выполнения Пролог-программы. Показывается, как с помощью предиката
"сократить" можно управлять пространством поиска программы. Там
представлено также множество предикатов, имеющихся в большинстве
версий языка Пролог. В гл. 4 дан сравнительный анализ различных под-
подходов к процессу прО1раммирования на Прологе. Читатель, изучающий
данную книгу подряд, к концу четвертой главы получит достаточно полное
представление о возможностях этого языка.
Сферы применения языка
В гл. 5-7 рассматриваются конкретные сферы применения языка
Пролог. В гл. 5 описаны средства для работы с текстами и представлены
программа-конвертер (с версии языка Пролог для ЭВМ DEC:10 на микро-
Пролог и обратно) и интерпретатор языка запросов. В гл. 6 рассказывается о
том, что означает представление знаний в про грамме дляЭВМ.Тамдаетсяоб-
чор некоторых видов вычислительных формализмов, используемых для
10 ПРЕДИСЛОВИЕ
представления знаний. Затем рассматривается реализация механизма насле-
наследования в Прологе. Изучаются некоторые практические случаи применения
механизма наследования, среди них — таблично-управляемая программа
выполнения запросов к базе данных, позволяющая производить нарастаю-
нарастающее уточнение запросов. В гл. 7 обсуждаются вопросы реализации интер-
интерфейса пользователя с системами экспертных консультаций и описывается
интерпретатор, который может пояснить, каким образом он Пришел к тем
или иным ответам. В качестве последнего примера в гл. 7 рассказывается
об интерпретаторе, который может успешно обрабатывать такие запросы,
которые вызывают бесконечное зацикливание обычного интерпретатора
языка Пролог.
Примеры текстов программ .
На протяжении всей книги автор старался представить достаточное
количество конкретных примеров, чтобы проиллюстрировать новый ма-
материал. Однако число примеров не столь велико, чтобы читатель "потонул"
в море программ. Примеры программ, приведенные в семи главах книги,
часто специально сделаны достаточно Простыми, чтобы читатель смог с
максимальной легкостью разобраться в них. В приложении II содержатся
тексты дополнительных программ, предназначенных для выполнения
экранного ввода-вывода, для сбора множества ответов и т.д.
Совместимые версии языка Пролог
Во всех примерах, приведенных в данной книге, автор придерживался
высоко портабельного подмножества версии языка Пролог для ЭВМ
DEC-10, которое полностью совместимо с тем, что Клоксин и Меллиш
называют "ядром Пролога". Говоря конкретно, приведенные программы
будут работать в следующих версиях языка Пролог: CProbg, Quintus,
Arity,- Prolog-1 и Prolog-2 фирмы Expert Systems International, UNSW
Prolog, Proiog-86, Chalcedony Prolog, IF/Prolog, micro-Prolog и Sigma
Prolog для ЭВМ DEC-10 и т.д. Многие программы будут работоспособны
и при их выполнении в системе Turbo Proiog. Фактически же все програм-
программы данной книги первоначально разрабатывались на диалекте CProlog,
а затем были перенесены на некоторые другие версии языка. Автор пы-
пытался избегать использования каких-либо средств или конструкций языка
Пролог, являющихся особенностями конкретных версий этого языка.
В приложении IV обсуждаются различия между версиями Пролога. Оно
может оказаться полезным справочным пособием при переносе программ
с одной версии языка Пролог на другую.
ПРЕДИСЛОВИЕ 11
Показательный пример
В Приложении III Приведен показательный пример, связанный с плани-
планированием работы в промышленном производстве. В этой прикладной
области требуется воспользоваться некоторыми усложненными методами
решения задач. Здесь вполне естественным образом употребляются многие
методы программирования и представления задач, описанные в данной
книге. И хотя в показательном примере применяется сильно упрощенная
модель производственного процесса, этот пример показывает общий
подход к решению данной задачи. В рамках этого подхода можно пред-
представить и реальные производственные процессы, если описать их с необхо-
необходимым уровнем сложности. Данный показательный пример призван про-
проиллюстрировать, как с помощью средств языка Пролог можно решать
достаточно сложную задачу.
Существует, однако, некоторая "опасность'" во включении в книгу
всего лить одного показательного примера. Если сфера применения, ил-
иллюстрируемая примером, окажется понятной лишь узкому Kpyiy специа-
специалистов, то читатели, че знакомые с обсуждаемым предметом, останутся
ракнодушными к такому примеру. Если же прикладная область будет
слишком широко известна, то предлагаемая программа не будет выполнять
сколь-либо важных действий, а это может разочаровать некоторых чита-
читателей. Сфера промышленного производства выбрана потому, что она на-
находится где-то между этими двумя категориями прикладных областей.
Она должна быть доступна даже тем, кто никогда не был связан с промыш-
промышленным производством. В то же время многие методы, используемые в
показательном примере, пригодятся и в других областях.
Существует и еще одна причина, по которой был выбран показатель-
показательный пример и! сферы промышленного производства. У многих людей
создается впечатление, что Пролог - это "академический" язык, непри-
непригодный для практических целей. Они спрашивают: "Что же можно реально
сд&шть при Помоши этого языка?" Ответом — хотя и не слишком убеди-
убедительным — могло бы стать перечисление всех тех вещей, которые можно
было бы реализовать на Прологе, упоминание академических исследова-
исследовательских проектов или намек на то, чго значительная часть действительно
серьезных работ, выполненных при помощи языка Пролог, является засек-
засекреченной. Однако гораздо более убедительно звучало бы перечисление
реальных, коммерческих программных систем, построенных на Прологе,
а родь именно в области промышленного производства и существует не-
несколько таких систем.
12 ПРЕДИСЛОВИЕ
Как ориентироваться в материале данной книги
Эту книгу можно читать подряд — от начала и до конца. Однако такому
порядку следовать не обязательно. Читатели, уже знающие Пролог, могут
непосредственно переходить к интересующим их темам. На полях книги*)
размещаются заголовки, облегчающие поиск нужных разделов. Имеется
также обширный предметный указатель, который поможет читателям
лучше ориентироваться в материале книги. Некоторые основные спе-
специальные термины поясняются в глоссарии в приложении I.
*)С целью экономии бумаги заголовки перенесены с полей в текст книги. - Примеч.
пер.
ВВЕДЕНИЕ
Зачем иужио изучать Пролог?
Нет сомнения в том, что при изучении нового языка программирова-
программирования потребуется значительная затрата сил и времени, поэтому целесообраз-
целесообразно коротко остановиться на причинах, которые могут побудить програм-
программиста к изучению языка Пролог. Все сводится к вопросу о том, какие
преимущества имеет Пролог по сравнению с другими языками при решении
прикладных задач.
Взгляд на мир, навязываемый языком программирования
Язык программирования навязывает пользователям определенный
взгляд на окружающий мир. Это проявляется в том, что программист,
длительное время пользующийся некоторым языком и усвоивший соот-
соответствующий этому языку взгляд на мир, будет стремшься находить
новые сферы применения для тех типов вычислений, к которым данный
язык приспособлен, и будет избегать задач, для решения которых этот
язык не годится. Предположим, что целью написания программы для ЭВМ
является либо решение определенной задачи, либо представление системы,
существующей в реальном мире, таким образом, чтобы программа могла
использоваться для моделирования поведения этой системы. Целесообразно
оценивать взгляды на мир, навязываемые различными языками програм-
программирования, в соответствии с тем, насколько хорошо они соответствуют
указанным выше целям. Данные рассуждения относятся к метапрограмм-
ной инженерии: задана цель программирования (см. выше); нужно опре-
определить, какие языки и программные средства наилучшим образом ей
удовлетворяют.
Семантика языков программирования
Один из путей исследования взглядов на мир, навязываемых языками
программирования, — это изучение семантики (смысла) языковых конст-
конструкций. Программирование при помощи конструкций некоторого языка
требует мышления в терминах семантики этих конструкций. Таким об-
обратом, семантика служит ключом к пониманию процесса мышления про-
L ВВЕДЕНИЕ
граммиста. Языки программирования можно разбить на три широкие
категории в соответствии с природой семантики этих языков: I) проце-
процедурные языки, 2) функциональные языки и 3) реляционные языки. Смысл
конструкции процедурного языка определяется в терминах поведения
компьютера при выполнении этой конструкции. Поведение может быть
либо внешним (например, вывод сообщения на терминал), либо внутрен-
внутренним (например, изменение значения переменной). Смысл конструкции
в функциональном1 языке (например, вызова функции) определяется
в терминах значения, которое она вырабатывает. Вызов функции можно
рассматривать как объявление вырабатываемого ею значения. Смысл
конструкции в реляционном языке определяется как отношение между
отдельными сущностями или классами сущностей. С декларатипной точки
зрения реляционную конструкцию можно интерпретировать как формули-
формулировку того, что существует отношение между аргументами, представлен-
представленное именем этого отношения.
Уровень языка
Предположим далее, что программист, приступающий к написанию
программы, располагает логической спецификацией, в которой четко
описана подлежащая решению задача или структура системы, которую
необходимо предс/авить. Это предположение позволяет провести класси-
классификацию взглядов на мир, навязываемых языками программирования,
в соответствии с уровнем языка по отношению к заданной спецификации.
Язык низкого уровня дает картину мира, близкую к взгляду на мир с
позшиш компьютера. Язык высокого уровня обеспечивает взгляд на мир,
приближающийся к картине мира, представленной в спецификации задачи.
Согласно этому критерию процедурные языки относятся к языкам низ-
низкого уровня. В соответствии с семантикой конструкций процедурного
языка программист должен мыслить в терминах конструкций, определяю-
определяющих поведение компьютера. При использовании процедурного языка
требуется проведение большой работы по переводу спецификации слож-
сложной системы в работоспособную программу. Функциональные языки
имеют более высокий уровень, чем процедурные, поскольку программист
может мыслить в терминах вычисления значений, а не поведения ЭВМ.
Сами же значения нередко являются частью спецификации. Реляционные
языки имеют наивысший уровень, так как семантика конструкций реля-
реляционного языка весьма близка к спецификации задачи. Взгляд на мир
для идеального реляционного языка будет таким же, как и взгляд на
мир с позиций логической спецификации, поэтому для преобразования
одного в другое понадобятся минимальные усилия. При использовании
идеального реляционного языка становится возможным написание про-
программы, структурно изоморфной по отношению к своей спецификации,
т.е. для каждой вариации формы спецификации будет существовать соот-
соответствующая вариация формы программы.
ВВЕДЕНИЕ 15
Преимущества реляционного образа мышления
Хотя Пролог и далек от идеального реляционного языка, он в то же
время достаточно близок к такому языку. Это позволяет программисту
воспользоваться упомянутыми выше преимуществами идеальных реля-
реляционных языков. При должном пользовании языком Пролог взгляд про-
программиста на мир может подняться до уровня спецификации. Если про-
программист сможет мыслить целиком в терминах структуры отношений,
не заботясь о точности их трансляции в программу (т..е. о реализации),
то у него освободится время для более важных целей. Иногда критикуют
Пролог за то, что он навязывает программисту логический взгляд на мир;
правда же состоит в том, что любой взгляд на мир можно выразить в виде
Пролог-программы*) . Именно поэтому на Прологе реализуются обширные
исследовательские работы в таких наиболее актуальных областях инфор-
информатики, как обработка естественного языка и экспертные системы. Наи-
Наиболее убедительный довод в пользу необходимости изучения Пролога
заключается в том, что данный язык позволяет работать специалисту в
этих областях на высоком концептуальном уровне.
Выражения признательности
Читатель, знакомый с литературой по логическому программирова-
программированию, поймет, насколько автор обязан идеям, принадлежащим в основном
двум исследователям - Бобу Ковальски и Пэту Хэйесу. Борджес написал
короткий рассказ об арабском ученом Аверроесе из Умайядской Испании,
который стал самостоятельно переводить работы Аристотеля с греческого
языка на арабский. В рассказе описывается, что произошло, когда он
встретил греческие слова, обозначающие "комедию" и "тра1едию". По-
Поскольку в исламской Культуре не существовало театров, понятия "коме-
"комедия" и "трагедия" как жанры драматургии были совершенно чужды его
жизненному опыту. Однажды после мучительных ночных попыток дога-
догадаться, что эти слова означают, он изобрел свои смысловые значения для
них. Эти .значения, как казалось ему, подчинялись той закономерности,
ч которой их использовал Аристотель. В действительности же данные
значения оказались (с нашей точки зрения) совершенно неправильными.
После того, как автор проделал исследовательскую работу с целью напи-
написания данной книги, он проникся большой симпатией к Аверроесу. Не-
Некоторые читатели, возможно, обнаружат, что автор допустил какие-то
ошибки в интерпретации, сходные с ошибками Аверроеса.
Среди лиц, принявших участие в создании этой книги, следует назвать
Гона Гомбаха, который, благодаря бесчисленным дискуссиям, помог
"^Предоставим читателю возможность самому сделать окончательное заключение
по этому вопросу. - Примеч. пер.
16 ВВЕДЕНИЕ
автору добиться ясности изложения и в самом начале работы над книгой
решил проверить, насколько Пролог годится в качестве языка для решения
задач, возникающих в сфере промышленного производства. Многие при-
прикладные примеры появились в этой книге благодаря любезности Рока.
Автор благодарит также Джона Штрузе, Ричарда Штрузе и Джона Розема-
на, которые предоставили драгоценное машинное время, когда у автора
не было своей ЭВМ, с помощью которой можно было бы изучить Пролог.
Автор выражает признательность Бобу Диднеру за то, что он предоставил
автору первую возможность построить на Прологе систему, ориентирован-
ориентированную на коммерческое применение. Поддержка Билла Йенсена, Билла Ро-
бертсона и Кейта Айзенштарка из фирмы Structured Methods, Inc. была
важна при разработке учебного курса по языку Пролог, на основе кото-
которого и была создана данная книга. Автор выражает признательность Кэ-
Кэти О'Лиэри за ее терпение при прослушивании бесконечных объяснений
по Прологу во время разработки учебного курса. Критика и предложе-
предложения Пэтти Кан, Дженнифер Циммерман и Ричарда О'Кифе (все — из фирмы
Quintus Computer Systems, Inc.) были просто бесценными. Отзывы сту-
студентов, посещавших учебный курс по Прологу, сыграли роль важной
обратной связи, позволившей уточнить изложение материала, представлен-
представленного в данной книге. Замечания лиц, прочитавших черновик книга, среди
которых были Дуг де Гроот, Джо МакДоноу, Лэрри Линч-Фрешнер и Дейв
Смит, оказали значительное влияние на итоговый вариант книги. Автор
хотел бы также выразить благодарность Бобу Хорну, Дэвиду Джонсону
и Патриции д'Андраде с Лексингтонской конференции, а также Джэку
О'Лиэри и Карлу Карл стрему за их поддержку.
При печати и редактировании первых вариантов черновика рукописи
книги использовалась система Writer's Workbench фирмы. AT&T. Форма-
Форматизация текста книги была осуществлена с помощью системы Documenter's
Workbench фирмы АТ& Т, при этом использовались не зависящая от типа
устройства программа troff, табличный препроцессор tbl и препроцессор
для обработки графических изображений pic. Предметный указатель был
сгенерирован автоматически с помощью системы Laserlink фирмы Urban
Software.
ГЛАВА О
ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
0.1. ЗНАКОМСТВО С ЛОГИЧЕСКИМ ПРОГРАММИРОВАНИЕМ
Определение логического программирования
Логическое программирование - это один из подходов к информати-
информатике, при котором в качестве языка высокого уровня используется логика
предикатов первого порядка в форме фраз Хорна. Начало исследованиям в
области формальной логики было положено работами Аристотеля в TV в.
до н.э. Логика предикатов первого порядка — это ветвь формальной логи-
логики, получившая развитие в основном в XX в. Это — универсальный аб-
абстрактный язык предназначенный для представления знаний и для решения
задач. Его можно рассматривать как общую теорию отношений. Логичес-
Логическое программирование базируется на подмножестве логики предикатов
первого порядка, при этом оно одинаково широко с ней по сфере охвата.
Логическое программирование дает возможность программисту описывать
ситуацию при помощи формул логики предикатов, а затем, для выполнения
выводов из этих формул, применить автоматический решатель задач (т.е.
некоторую процедуру). При использовании языка логического программи-
программирования основное внимание уделяется описанию структуры прикладной за-
задачи, а не выработке предписаний компьютеру о том, что ему следует де-
делать. Другие понятия информатики из таких областей, как теория реля-
реляционных баз данных, программная инженерия и представление знаний,
также можно описать (и, следовательно, реализовать) с помощью логичес-
логических программ. С этой позиции логическое программирование оказывает
потенциально революционизирующее влияние на многие аспекты инфор-
информатики.
Пролог
Обычно в языках логического программирования применяется про-
программная технология, основывающаяся на правиле вывода путем резолю-
резолюции, которое предложил Робинсон. Пролог — это наиболее известный
язык логического программирования. Существуют, однако, и иные языки.
Первоначальный вариант языка Пролог был разработан Алэном Кольмеро-
ром с сотрудниками в 1972 г. в Марсельском университете. В течение по-
последнего десятилетия этот язык получил дальнейшее развитие благодаря
18 ГЛ.О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
работам, проводившимся в различных университетах Европы. Лишь начи-
начиная с 1981 г. Пролог стал привлекать внимание специалистов из США.
Это произошло после того, как Министерство внешней торговли и развития
Японии объявило о том, что японский проект,создания ЭВМ 5-го поколения
будет основываться на методах логического программирования. С этого
момента интерес к Прологу непрерывно рос. Теперь Пролог применяется
для решения прикладных задач многими правительственными организа-
организациями и фирмами Европы, США и Японии. Сейчас существует международ-
международное сообщество ученых и специалистов, активно работающих в области ло-
логического программирования. Японские исследователи играют важную
роль в этих работах.
Язык искусственного интеллекта
Пролог часто называют языком искусственного интеллекта. Такая
формулировка, однако, некорректна в двух отношениях. Лисп — это наи-
наиболее известный язык искусственного интеллекта. Если определить анало-
аналогичным образом сферу применения языка Пролог, то неизбежно начнется
сопоставление этих двух языков с целью выявить, какой из них лучше.
С точки зрения практики для каждого языка существует своя методология
программирования. Единственно приемлемый способ сравнения языков,
дающий основания заявить, что один язык "лучше" другого, заключается
в учете "человеческих" факторов, т.е. в сравнении читабельности программ,
легкости в пользовании языками и т.д. В настоящее время американские
специалисты по искусственному интеллекту отдают предпочтение языку
Лисп. Их выбор скорее обусловлен привычностью Лиспа, чем недостатка-
недостатками языка Пролог как такового.
Более важным моментом является то, что сфера применения Пролога
не ограничивается искусственным интеллектом. Этот язык успешно исполь-
использовался как для решения многих традиционных прикладных задач (про-
(программная инженерия, интерфейсы баз данных, системы помощи в приня-
принятии решений), так и для решения задач искусственного интеллекта
(экспертные системы, системы обработки естественного языка).
Про сто та язы ка Пролог
Язык программирования Пролог привлекателен своей простотой
(в нем насчитывается небольшое количество лексикографических симво-
символов). Пролог-программу легко читать, что является фактором, способ-
способствующим повышению производительности при программировании и уве-
увеличению удобств при сопровождении программ. Поскольку язык Пролог
основан на универсальных формализмах фраз Хорна, исходный текст
Пролог-программ значительно менее подвержен влиянию машинно-зависи-
машинно-зависимых особенностей, чем исходные тексты программ, написанных на других
языках. Кроме того, в различных версиях языка Пролог проявляется
0.2. ТРАДИЦИОННАЯ ЛОГИКА j9
тенденция к единообразию, так что программу, написанную для одной вер-
версии, легко можно преобразовать в программу для другой версии этого
языка. В конечном счете Пролог прост в изучении.
Наследие логики
Логическое программирование имеет своими корнями формальную
логику. Для того чтобы оценить логическое программирование по достоин-
достоинству, необходимо понять суть формальной логики и познакомиться с исто-
историей ее развития. В разд. 0.2-0.7 обсуждаете" эволюция логики, при этом
^сначала рассматриваются первые результаты по кодификации традиционной
ротики, а затем — современная логика предикатов и начала логического
программирования. В разд. 0.8—0.11 раеек1зывается об отличительных
особенностях логического программирования и языка Пролог с точки зре-
1Тния технологии программирования.
[• 0.2. ТРАДИЦИОННАЯ ЛОГИКА
!¦'¦
а.
\ Аристотель
\ ' То, что теперь известно как "традиционная логика", начало развиваться
(Во времена Аристотеля более 2,2 тыс. лет назад. Аристотель попытался
исвести в научную систему способы, с помощью которых можно наиболее
[эффективным образом постигать истину в разумной полемике. Его рабо-
\ху лучше всего охарактеризовать как теоретическое исследование методов
I правильных рассуждений.
| Законы логики
v При формализации логики Аристотель стремился установить некото-
некоторый критерий, в соответствии с которым можно было бы определить пра-
1'вильность хода рассуждений в разумной полемике. Здесь при описании
; логики Аристотеля употребляется слово "суждение". Оно обозначает за-
j конченную мысль, которую можно выразить при помощи простого выраже-
|Ния естественного языка. Три закона традиционной логики, сформулиро-
сформулированные Аристотелем (см. табл. 0.1), являются попыткой установить ирави-
|ла, регулирующие использование суждений в полемике.
I Назначение законов логики состоит в обеспечении целостности сужде-
?ний. Эти законы гласят, что суждение всегда должно иметь единственное
'значение истинности — истина или ложь, и данное значение не может
^изменяться по желанию одного из участников полемики. После того, как
[признано правильным значение истинности некоторого суждения, проти-
противоположное значение истинности для этого же самого суждения уже не мо-
кжет быть признано^ верным. Если приведенные законы не соблюдать (на-
20 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ;
Таблица 0.1 >'
Законы традиционной логики
Тождественность А является А
(некоторая вещь всегда равна самой себе; суждение означает само себя)
Противоречие А не является не-А
(вещь не может одновременно обладать и не обладать некоторым свойством; никакое
суждение не является одновременно истинным и ложным) '<
Исключение среднего А не является одновременно и А, к не-А
(вещь либо обладает, либо не обладает некоторым свойством; каждое суждение либо
истинно, либо ложно)
пример, если в дискуссии одновременно используются и первоначальное!'
суждение А, и последующее суждение, которое противоречит А), то любое, i
умозаключение, получаемое в ходе полемики, будет недостоверным.
Элементы суждения
Согласно Аристотелю суждение состоит из четырех элементов: : -
Квантор Субъект Связка Предикат. '
Например, в суждении ,
Все американцы являются водителями машин. *.!¦¦
"американцы" - это субъект, "все" квантифицирует субъект, т.е. это - ,
квантор, "водителями машин" - это предикат, а "являются" — связка.,
В суждении
Некоторые водители такси не являются агрессивными.
"водители такси" - это субъект, "некоторые" - квантор, "не агрессивны-^
ми" - предикат, а "являются" — связка. ,
Четыре формы суждений > >
В традиционной логике допускаются четыре формы суждений, каждая; (
из которых характеризует возможное отношение между двумя классами:
Все S являются Р. »
Никакой из S не является Р. ;;
Некоторые из S являются Р.
Некоторые из S не являются Р. . {
0.2. ТРАДИЦИОННАЯ ЛОГИКА 21
Здесь S обозначает класс субъектов, а Р — класс предикатов. "Все" или
"никакой и а" нал>ыаюгсл универссигьными кванторами, или кванторами
общности. Они применимы к каждому элементу заданного класса субъек-
субъектов. "Некоторые из" называется экзистенциальным квантором, или кванто-
квантором существования. Он относится к подмножеству класса субъектов.
Силлогизм
Силлогизм - это множество правил, определяющих то, какие умо-
умозаключения могут быть получены из множества суждений, каждое из ко-
которых записано в одной из четырех допустимых форм. Например, он пока-
показывает, что если заданы две такие предпосылки (т.е. суждения, которые
полагаются верными):
Все американцы являются водителями машин. A)
Все калифорнийцы — американцы. B)
то будет корректным умозаключение:
Все калифорнийцы являются водителями машин. C)
Процесс выработки умозаключения на основе предпосылок называется
также выполнением вывода. С формальной точки зрения процесс вывода,
ехидный с приведенным выше, можно выполнить только тогда, когда класс
предикатов одного суждения (например, "американцы" в выражении B))
согласуется с классом субъектов другого суждения (например, "американ-
"американцы" в выражении A)). В результате вывода на основе субъекта одного
суждения и предиката другого суждения формируется новое суждение.
Силлогизм устанавливает разные результаты для различных типов кванти-
фикации. Например, из суждений:
Все бейсболисты - любители жевательной резинки. D)
Некоторые бейсболисты живут в Бостоне. E)
получается умозаключение:
Некоторые (люди) из Бостона - любители жевательной резинки. F)
Силлогизм — это прежде всего логика классов. В предыдущем примере
участвовали классы бейсболистов, любителей жевательной резинки и лю-
людей, живущих в Бостоне. Все силлогистические правила основываются на
свойстве транзитивности операции включения в состав класса. Транзитив-
Транзитивность - это свойство, присущее некоторым видам отношений. Возьмем,
к примеру, арифметическое равенство. Если известно, что а = b и b = с,
то, согласно свойству транзитивности, а = с. Операция включения одного
класса в состав другого класса также обладает свойством транзитивности.
Если класс А входит в состав класса В (например, в суждении: "Все бейс-
бейсболисты — любители жевательной резинки"), а класс В входит в состав
класса С, то класс А должен входить в состав класса С.
22 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛО^
Каждое правило силлогизма определяет переход ос предпосылок к
умозаключению, являющемуся интуитивно очевидным. Если сложная
дискуссия состоит из многих дедуктивных шагов, то вся она будет логи-
логически правильной (и, надо надеяться, понятном) « тм случае, если каждый
ее шаг можно объяснить при помощи силлотеги ач кого правила.
Высказывания
Ученики Аристотеля, основываясь на понятии силлогизма, выделили
принципы дедуктивного вывода для' более высокого уровня абстракции —
для высказываний. Высказывание — это любое суждение, которому мож-,
но приписать истинностное значение (либо истина, либо ложь). Высказыва-
Высказывание эго более обшее понятие, чем суждение в сиплпгизме. 1С примеру,
выражение
Единорог XYZ существует.
является высказыванием, но не силлогистическим суждением, так как оно
не соответствует ни одной из четырех приведенных выше форм суждений.
Последователями Аристотеля были получены правила дедуктивного
вывода для высказываний. Эти правила перечислены в табл. 0.2. Буквы
Р и Q — это переменные, которые могут представлять любое конкретное
высказывание.
Данные правила представляют собой гораздо более общий метод вы-
вывода, чем исходный силлогизм. Они являются первым шагом к созданию
логики высказываний. Такая логика (исчисление высказываний) была
полностью разработана лишь в XIX в.
Позиции традиционной логики
С философской точки зрения традиционная логика тесно связана
с представлениями о статичности мира, принятыми в Древней Греции.
Понятие тождества (или истинностного значения) при гаком подходе не до-
Таблица 0,2
Правила вывода
Modus Ponendo Ponens Если из Р следует Q и Р истинно, то и Q истинно.
Modus Tollendo Tollens Если из Р следует Q « Q ложно, то и Р ложно; >
Modus Ponendo Tollens - Если Р и Q не могут одновременно быть истнЯ-
ными и Р истинно, то Q ложно (исключающее
"нли").
Modus Tollendo Ponens Если либо Р. либо Q является истинным и
Р Не истинно, то Q истинно
(дизъюнктивный силлогизм) (включающее "или").
0.2. ТРАДИЦИОННАЯ ЛОГИКА 23
пускает изменений. После того, как было установлено некоторое тождест-
тождество, оно сохраняется неизменным. Три закона из табл. 0.1 кратко выражают
это положение: суждение должно обладать истинностным значением, причем
только одним. Эта позиция не способствует развитию эмпирических наук,
в которых требуется учитывать изменения. Поэтому в XVII—XVIII вв. —
в период развития областей науки, связанных с экспериментами, — интерес
к логике Аристотеля упал.
Критика силлогизма
Неизвестно, к худшему это было или к лучшему, но логика Аристотеля
получила такое признание, что вплоть до XIX в. никто даже не помышлял о
ее совершенствовании. Целые поколения студентов изучали основной
научный труд Аристотеля по логике и запоминали силлогизмы наизусть.
Любопытно отметить, что в неопубликованных работах Лейбница
A646-1716 гг.) не было ни теНи сомнения в совершенстве логики Аристо-
Аристотеля. Лейбниц обнаружил четыре случая, для которых, как казалось, силло-
силлогизм был неверен или неполон. Лейбниц, однако, посчитал, что где-то
сам допустил ошибку (ведь Аристотель был безупречен!), и вместо того,
чтобы привлечь внимание других ученых к твоему открытию, умолчал
об обнаруженных несоответствиях.
¦ Но Лейбниц нанисгм i юм, что предвидит создание нового, универсаль-
универсальною языка математической логики, призванного заменить силлогизм. Он
ржидал, чн> такой язык даст возможность решать философские проблемы
чисто механическим образом, что принесет в наш мир спокойствие и гар-
гармонию. Лейбниц думал, что наступит время, когда два человека, имеющие
разногласия, вместо разрешения спора силой употребят этот язык, кото-
который позволит им узнать правильное решение по предмету их спора.
Неадекватность силлогизма
Силлогизм как теория чрезмерно сложен и неполон. Он является логи-
логикой классов, однако не содержит понятия дополнения класса. (Если А —
класс, то дополнение класса А содержит все элементы, не входящие в А).
Так, для выполнения некоторых выводов требуется введение классов,
определяемых через отрицание (т.е. негативно), например, "класса всех лиц,
не являющихся водителями машин". В силлогизме отсутствует механизм
или форма записи, позволяющая выполнить переход от негативно опреде-
определяемого класса к позитивно определяемому классу.
Силлогизм призван управлять разумной дискуссией на естественном
языке, но он слишком тесно связан с самим естественным языком. Это
приводит к абсурдным результатам, скажем, логики отрицали логическую
эквивалентность двух способов выражения одной и той же мысли. Напри-
Например, в большинстве случаев утверждение
it. Все программисты суть логики.
24 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
означает то же самое, что и
Если некто является программистом, то он или она также является ¦
и логиком
К сожалению, силлогизм не позволяет работать со вторым суждением, '
так как оно не принадлежит к одной из четырех допустимых форм сужле-.
ний. (Для того чтобы проблема была разрешимой при помощи силлогизма, ,
она должна быть представлена в виде совокупности суждений, принадлежа-
принадлежащих к четырем допустимым формам.)
Силлогизм неполон в том смысле, что он не позволяет проводить'
логические выводы, в которых затрагиваются вопросы существования
элемента некоторого класса. Кроме того, многие формы верных силло-
силлогистических выводов излишни. Их можно полностью удалить, при этом
свойства силлогизма как дедуктивной системы нисколько не ухудшатся.
Итак, силлогизм представляет собой интересную попытку формали-
формализации дедуктивного мышления. В настоящее время спеииалисты по фор^;
малыши логике считают силлогизм неким научным курьезом, не имеющим [
значения для развития современной формальной логики. Удивительным i
обстоятельством является то, что в течение столь долгого периода силло- i
гизм без каких-либо сомнений считался нормативной формой всех ра-
рациональных процессов мышления.
0.3. НАЧАЛЬНЫЙ ПЕРИОД РАЗВИТИЯ ФОРМАЛЬНОЙ ЛОГИКИ
Де Морган
Первый шаг к логике высказываний, или исчислению высказываний}'"
был сделан учениками Аристотеля, когда они получили множество правщ|г.
вывода, которые применимы к высказываниям. Наиболее простым и са\
мым важным из этих правил является правило modusponens: •,
Если из Р следует Q, а Р — истинно, то и Q будет истинным. k
Следующие шаги в развитии логики высказываний связаны с работами"
английского математика Де Моргана, выполненными в середине XIX в.
Дс Морган критиковал Аристотеля за то, что законы логики были записаны
на естественном языке. Он полагал, что формальный смысл силлогистичес-
силлогистических суждений искажается семантикой естественного языка. Он хотел
построить чисто формальную систему логики, т.е. язык, дакшшй возмож-
возможность выполнять адекватные манипуляции с символами независимо от то-
того, какой смысл приписывается этим символам, В качестве образца он
взял алгебраическую форму записи. В выражении х + у х и у можно интер-
интерпретировать как нечисловые величины, а + может вместо сложения обозна-
обозначать другую операцию. Правила действий с алгебраическими выражениями
имеют исключительно синтаксическую (формальную) природу, поэтому
0.3. НАЧАЛЬНЫЙ ПЕРИОД РАЗВИТИЯ ФОРМАЛЬНОЙ ЛОГИКИ 25
они сохраняют силу даже тогда, когда алгебраические символы интерпрети-
интерпретируются иным образом. В силлогизме слова "есть, является", входящие в
суждение (например, «все S являются Р»),~всегда интерпретировались как
отношение включения в класс (в данном примере класс Р включает все
элементы множества S). Де Морган хотел освободить слова "есть, являет-
является" от этого смысла и распространить их на все отношения, обладающие
свойством транзитивности. Поэтому он ввел общее понятие отношения как
абстрактного качества, связанного с обладанием любыми разнообразными
свойствами (например, транзитивностью, симметрией и рефлексивностью).
Буль
Английский математик Буль, современник Де Моргана, также внес
вклад и разаитие логики высказываний. Он считал, что главное в логике —
это форма, а не содержание. Буль рассматривал логику как разновидность
нечисленной алгебры классов. Логика Аристотеля всегда была тесно связа-
связана с философией, а Буль принял точку зрения, в соответствии с которой
логика вместо этого должна ассоциироваться с математикой. Используя
знакомые алгебраические символы, он показал, что некоторые алгебраичес-
алгебраические правила равным образом применимы к числам, множествам и истин-
истинностным значениям высказываний.
Интерпретации алгебраических правил
Рассмотрим пять правил, описывающих алгебраические действия с
символами (см. табл. 0.3). Вначале будем считать, что хи у имеют обычный
смысл и обозначают числовые переменные, + обозначает операцию сложе-
сложения, а * обозначает умножение. Например, если значение х равно 3, а зна-
значение у равно 4, то в результате как действия х + у, так и действия у + х
получится значение 7.
Далее примем, что х и у - это переменные, значениями которых яв-
являются множества, + обозначает операцию объединения двух множеств.
Таблица 0.3
Правила алгебраических действий
х + у - у + х коммутативность
х * у = у * х
х + (у + z) = (.х + v) + т ассоциативность
X * (у * z) = (х * у) * z
%*
аг * {у + z) = (х * у) + (х * г) дистрибутивность
26 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
а * обозначает пересечение двух множеств. Например, если значением х
служит множество {1, 2, 3), а значением у — множество {3, 4, 5), то в ре-
результате как действия х + у, так и действия у + х получится множество
{1,2,3,4,5}.
В заключение положим, что х и у - это переменные, значениями кото-
которых являются высказывания, + обозначает операцию "или", * обозначает
операцию "и", а = обозначает логическое равенство. Например, если х — это
высказывание со значением истина, а у - это высказывание со значением
ложь, то значением как действия х + у, так и действия у + х будет истина.
Операция ~
Приведенные выше правила образуют внутренне непротиворечивый
формальный язык, поскольку они сохраняют правильность в трех различ-
различных интерпретациях. (Этот язык позже стали называть булевой алгеброй?)
К этому языку, при интерпретациях для множеств и истинностных значе-
значений, можно добавить еще один символ , который обозначает унарную
операцию и ставится перед выражением. Унарная операции - это операция,
в которой участвует один аргумент. При интерпретации для множеств'
символ ~ означает "дополнение для". В этом случае выражение
~(х*у)
представляет собой дополнение для пересечения двух множеств — х и у.
Это дополнение состоит из элементов, которые содержатся либо в множест-.
ве х, либо в множестве у, но не в обоих множествах сразу.
В интерпретации для высказываний символ ~ означает "не", т.е. в при-
веденном выше выражении этот символ обозначает обратное истинностное
значение для х * у (т.е. исключающее или для х и у).
Если стоят подряд два символа ~, то они нейтрализуют друг друга.
Это правило представлено в табл. 0.4.
Правила Де Моргана
Де Морган ввел в свой формальный язык два правила, которые приме-;
нимы при интерпретациях для множеств и высказываний. Они известны.^
как правила двойственности Де Моргана (см. табл. 0.5). (Совпадают ли эти
Таблица 0.5
Таблица 0.4 "
Правило двойного отрицания
Правила
-(**>¦)
Де
Моргаиа
= ~х * ~у
= ~х + ~у
0.3. НАЧАЛЬНЫЙ ПЕРИОД РАЗВИТИЯ ФОРМАЛЬНОЙ ЛОГИКИ
27
правила по смыслу с Вашими интуитивными представлениями при интер-
интерпретациях для множеств и высказываний?)
Таблицы истинности
Интерпретация любого выражения этого языка для высказываний мо-
может быть представлена таблицей истинности. Например, в табл. 0.6 приво-
приводятся значения истинности некоторых простых выражении.
X
Г
Г
У
т
F
X
F
F
~у
F
Т
х * у
Т
F
Та
.V + }¦
Т
т
б л и ц а- 0.6
~(х * у)
F
Т
Вторую строку данной таблицы можно прочесть так: если значением х
является высказывание, которое истинно (true) (обозначено как Т),
. а значением у — высказывание, которое ложно (false) (обозначено
как F), то значением истинности ~х будет ложь, значением ~у будет исти-
истина, значением х * у - ложь, значением х + у — истина, а значением ~(х * у) —
истина'
0.
Импликация
Импликация (т.е. следование) вида
если х, то у
|:где х и у — истинностные значения, может быть записана как
| у
L-Уочный смысл этого отношения задается в табл. 0.7.
^ Интересно отметить, что (хотя это в какой-то степени противоречит
итуитивным представлениям) если х — ложно, то у может принимать
яюбые значения, а итоговое значение импликации все равно будет истинно.
Таблица 0.7
X
т
т
у
Т
F
~ х + у
Т
F
X
F
F
У
Т
F
~х + у
Т
т
' *) Обычно в литературе значение истинно (или истина) обозначается как 1, а зна-
г чение ложно (или ложь) - как 0. - Примеч. пер.
28 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛО1*
Фреже и Пеано
Начало эры современной формальной логики можно связать с работой
Готтлоба Фреже, появившейся в 1879 г. Как и его современник Пеано,
Фреже стремился разработать чисто формальный логический язг.1К, который
мог бы служить основой арифметики. Серьезная проблема для Фреже й
Пеано заключалась в необходимости найти логические средства для пред*
ставления понятия последовательности, что позволило бы формально one»
рировать с множествами чисел. Фреже считал, что работы Буля и Де Морга»
на вносят некоторую путаницу, так как в них используется одинаковая
система обозначений и для арифметики, и для логики (знаки +, * и т..1?,.)';'-
Фреже создал "концептуальный язык'" ("begriffsschift1") — символическое
исчисление, позволяющее представлять и выполнять действия члг чисто
логическими формами, которые не зависят от числовых аналогий.
Фреже счи»ал, что интерпретация булевой алгебры с точки зрения выс-
высказываний является фундаментальной. В его .версии логики высказываний
из двух исходных соединителей — "импликация" и "отрицание" — можнс&
вывести все остальные соединители ("и", "или" и т.д.).
Теория отношений
В силлогистической логике принималось, что суждение, обладающее
истинностным значением, состоит из субъекта и предиката (см. разд. 0.2),
Другим нововведением Фреже было то, что суждение, обладающее :шаче«
нием истинности, стало считаться состоящим из предиката и некоторого
количества аргументов. Для записи таких суждений он применил условные
обозначения, сходные с математическими обозначениями функций. Фреже
провел аналогию между компонентами суждения и компонентами естест-
естественного языка, к примеру, такого предложения:
Вы читаете книгу.
Аргументы - это слова, которые могут изменяться в таких пределах»
пока выражение остается осмысленным. Например, слово "книгу" можно;
заменить на "газету", "Вы" — на "Я", при этом выражение сохранит ос*
мысленность * ). Предикат, с другой стороны, — это такая часть выражения»
изменение которой не может не повлечь за собой серьезного изменения
смысла и даже может привести к бессмыслице. Представьте, к примеру/
что произойдет, если слово "читаете" будет заменено на слово "едите",
Целью Фреже было создание общей теории отношений. Разбиение выс-
высказывания на предикат и аргументы - это существенная отличительная
особенность его теории. Фреже признавал также тот факт, что его теорий
*)Если учесть спряжение глагола "читать" в русском языке. - Примеч. пер.
0.4. ЛОГИКА ВЫСКАЗЫВАНИЙ 29
нуждается в средствах, позволяющих квантифицировать переменные,
являющиеся аргументами предиката. После Фреже общая теория
отношений получила название логики предикатов,
Исчисления
Подробный рассказ об истории развития формальной логики в XX в.
выходит за рамки данной книги. Одним из факторов, делающих такой рас-
рассказ практически невозможным, служит то обстоятельство, что система
обопаче; ий, принятых в формальной логике, эволюционировала столь
же быстро, как и сама эта наука. Почти каждый ученый-логик двадцатого
столетия использовал свою систему обозначений, отличную от систем,
употребляемых другими учеными. Это имело место по крайней мере вплоть
До недавнего времени, пока не установились в качестве стандартных не-
несколько систем обозначений. В оставшейся части данной главы автор но-
Пьпался использовать наиболее удобные логические обозначения (символы
которых можно напечатать в коде ascii!).
Поэтому вместо исторического рассказа в следующих двух разделах
дается неформальный обзор логики высказываний и логики предикатов.
Это готовит читателя к обсуждению в разд. 0.6 правила резолюции - основ-
основного правила вывода в логическом программировании. Автор намеренно
прибегает к нестрогому стилю изложения. Для полного ознакомления
с обсуждаемыми темами читатели могут обратиться к работам, список
которых приводится в конце главы.
0.4. ЛОГИКА ВЫСКАЗЫВАНИЙ
Высказывания
В соответствии с общепринятым лексиконом логики высказываний
символы А, В, С и т.д. применяются для обозначения атомарных высказы-
высказываний (т.е. высказываний, которые нельзя разбить на компоненты). От-
Отличительной особенностью высказывания является то, что оно обладает
истинностным значением - истина или ложь.
В некоторых случаях полезно представить, что один из этих символов
обозначает высказывание, выраженное на естественном языке. Предста-
Представим, например, что символ А обозначает предложение естественного языка:
Земля вращается вокруг Солнца.
Можно описать эту ситуацию, говоря, что данное предложение является
неформальным смыслом А. Поскольку в этом предложении утверждается
Нечто такое, что мы принимаем за истину, то значением истинности данного
предложения будет истина. В общем случае логика высказываний занима-
занимается только истинностными значениями символов и формул, построенных
из этих символов. Тот факт, что некоторый символ имеет определенный
30
ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
неформальный смысл, с логикой высказываний непосредственно не
связан. Неформальный смысл символов, однако, становится важным, когда
мы используем методы логики высказываний применительно к конкрет-
конкретной области знаний.
Правильно построенные формулы
Сложные формулы в логике высказываний можно строить щ тем ком-
комбинирования символов, представляющих атомарные высказывания, с ло-
логическими соединителями, приведенными в табл. 0.8.
Сложная формула, включающая логические соединители, называется
правильно построенной формулой (ППФ). В лексиконе логики высказы-
высказываний символы р, q и г обозначают пропозициональные переменные. Про-
Пропозициональные переменные используются для обозначения Ш1Ф. ППФ
можно определить следующим образом:
1. Символ, представляющий атомарное высказывание (например, А), —
это ППФ. " . .
2. Если р и q - это ППФ, го ППФ будут и такие формулы:
ППФ Читается так:
~ р не р ¦
р & q p и q \']
р v q р или q f!
Р —- > q если р, то q; p имплицирует q
р < > q p тогда и только тогда, когда q; :
р эквивалентно q.
Каждое из приведенных выше выражений с р и q называется предлож-
предложной формой. Предложная форма — это абстрактная спецификация синтак-
синтаксиса бесконечного числа ППФ, составленных из символов, представляющих
атомарные высказывания. Предложная форма — это либо единственная
пропозициональная переменная (к примеру, р), либо комбинация про-
пропозициональных переменных, связанных соединителями. ППФ, синтакси-
синтаксически согласующаяся с предложной формой, называется конкретной под-
Таблица 0.8
Логические соединители
Символ
Смысл
Символ
Смысл
не
>
< >
следование
{импликация)
тогда и только
тогда, когда
0.4. ЛОГИКА ВЫСКАЗЫВАНИЙ 31
становкой для предложной формы. Например, если А, В и С — это символы,
обозначающие атомарные высказывания, то ППФ
A&(BVC)
будет конкретной подстановкой для следующих предложных форм:
A) р (робозначает А & (В V С))
B) р & q (p обозначает А;
q обозначает (В V С) )
C) р & (г V q) (p обозначает А;
г обозначает В;
q обозначает С)
Истинностное значение ППФ
Форма, в которой записывается ППФ (иными словами, метод, которым
она конструируется из атомарных высказываний и логических соедините-
соединителей) , называется синтаксисом ППФ. Истинностное значение ППФ называют
семантикой или смыслом ППФ. Остается рассмотреть истинностные значе-
значения ППФ, включающих логические соединители.
При формальном изложении логики высказывания некоторые соеди-
соединители считаются исходными (или примитивными), а их смысл опреде-
определяется таблицей истинности. В этом случае смысл непримитивных соедини-
соединителей выводится через смысл исходных соединителей. Предположим, что
~, & и V — это примитивные соединители. Их смысл задается табл. 0.9:
Таблица 0.9
р
т
т
F
F
Смысл соединителей
Я
Р
Т F
F F
Т Т
F Т
~, & и V -
P&.Q
т
F
F
F
рЧя
Т
Т
Т
F
Теперь можно при помощи примитивных соединителей определить
смысл соединителей > и < > (см. табл. 0.10).
В таблице истинности (табл. 0.11) смысл этих соединителей опреде-
определяется явно.
Значение истинности ППФ, например,
А&В (*)
можно установить только с учетом конкретной интерпретации. Интерпре-
32
ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Таблица 0.10
Определение соединителей
Название
импликация
эквивалентность
Р
я \ р -
Т Т
Т F
Форма записи
р - ->
р< :
Смысл соединителей —
Г
F
Р<-->я1
т
F
Я
->
Г
F
Р-
> и < - -
|
>
Определение
~p\/q
(p&q) V (~Р & ~q)
и < >
</
Г
F
Таблица О.И
Р -->Я
р< > q
Т - F
Т Т
тация ППФ заключается в присваивании, истинностных значений каждому
атомарному высказыванию, входящему в ППФ. Предположим, что в одной
из интерпретаций А имеет значение истина и В — также истина. Тогда истин-
истинностным значением ППФ (*) при данной интерпретации будет истина.
При другой интерпретации истинностным значением ППФ (*) может
быть ложь.
Семантические свойства ППФ
Предположим, что ППФ, представленная пропозициональной перемен-
переменной р, истинна при некоторой конкретной интерпретации I. Тот факт, что
интерпретация I делает переменную р истинной, можно выразить любым
из следующих способов:
I удовлетворяет p. \ i
I есть модель р. . ,|
I подтверждает р.
р истинна при I.
Тавтологии и противоречия
Существуют некоторые ППФ, имеющие определенные истинностные
значения, обусловленные синтаксической формой этих формул, вне зависи-
зависимости от значений истинности атомарных высказываний, из которых эти
НПФ состоят. Например, значением ППФ
AV~A
всегда будет истина, независимо от значения А. Про такую ППФ говорят,
что она тождественно истинна, ее называют тавтологией.
0.4. ЛОГИКА ВЫСКАЗЫВАНИЙ 33
С другой стороны, истинностным значением ППФ
В&~В
всегда будет ложь, независимо от значения В. Про такую тождественно
ложную ППФ говоря, что она непоследовательна, ее называют противо-
противоречием.
Теории и аксиомы
Для того чтобы использовать методы логики высказываний примени-
применительно к конкретной области знаний (так называемой "предметной об-
области"), сначала необходимо проанализировать структуру этой области.
При выполнении анализа отыскиваются атомарные высказывания, дейст-
действующие в указанной области, и логические взаимосвязи, существующие
между этими атомарными высказываниями. После отбора соответствующе-
соответствующего множества таких атомарных высказываний следует подобрать обозна-
обозначения (скажем, символы А, В, С и т.д.) для представления каждого вы-
высказывания. После того как обозначения будут подобраны, неформальным
смыслом каждого из них будет некоторое атомарное высказывание из
заданной области знаний. Тем самым становится возможным описание
логических взаимосвязей между этими высказываниями, что достигается
посредством использования ППФ, сконструированных из соответствую-
соответствующих обозначений. Множество ППФ, сгенерированное таким путем, на-
называется теорией заданной области знаний, а каждая отдельная ППФ
именуется аксиомой.
Цель теории заключается в описании нужных знаний столь эконо-
экономичным способом, насколько это возможно. Если теория адекватно
описывает заданную область знаний, то все факты из области знаний,
являющиеся истинными, будут следствиями аксиом этой теории, а ни
один факт, являющийся ложным, не будет следствием данных аксиом.
Если все истинные факты из заданной области знаний являются след-
следствиями теории, то такая теория называется полной.
Рассмотрим пример для очень простой области знаний, касающейся
некоего лица по имени Дэвид и его отношения к логике. Все, что мы
знаем об этой области, содержится в следующих предложениях естест-
естественного языка:
Если Дзвид интересуется логикой, то он либо запишется
в следующем семестре на занятия по курсу Логика-101,
либо он ленив.
Если Дзвид самостоятельно изучал литературу по логике,
то он интересуется логикой.
Дэвид самостоятельно изучал литературу по логике.
Дэвид не ленив.
2. Дж. Малпас
34 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Из приведенных знаний можно выделить следующие высказывания и
подобрать обозначения для представления этих высказываний:
Высказывание Обозначение
Дэвид интересуется логикой. D
Дэвид запишется в следующем семестре
на занятия по курсу Логика-101. А
Дэвид ленив. В
Дэвид самостоятельно изучал литературу
по логике. С
Так, например, неформальным смыслом обозначения D будет высказы-
высказывание: "Дэвид интересуется логикой". Теперь можно использовать эти
обозначения для написания аксиом, описывающих то, что известно о
заданной области знаний. Тем самым будет построена теория этой об-
области знаний. Вот эта теория:
Пример теории
D --> AVB (О
С - - > D . ' B)
С C)
~В D)
Аксиома A) гласит, что если D истинно, то истинным будет А или!
В. Аксиома B) утверждает, что если С истинно, то будет истинным и БД
Аксиома C) гласит, что С истинно. Аксиома D) утверждает, что В ложно, $
Методы доказательства
В логике высказываний существуют методы доказательства того,!
является или нет конкретная ППФ следствием аксиом теории. Для это»!
го имеются два пути: первый из них основан на семантике (т.е. на ион-
тинностных значениях) нужных ППФ, а второй - на синтаксических пре-*
образованиях ППФ.
Обратимся к приведенному выше примеру теории. Предположим,
что требуется определить, является ли ППФ
А
логическим следствием аксиом этой теории.
Семантические методы доказательства
Если воспользоваться простым семантическим методом, то нужно
проверить все модели множества аксиом (модель — это интерпретация,
при которой каждая аксиома истинна). Здесь необходимо рассмотреть
каждое возможное присваивание значений истинности атомарным выска-
высказываниям в аксиомах (т.е. A, B.ChD), которое делает аксиомы истин-
истинными. Обратите внимание, что, поскольку аксиома C) гласит, что С
0.4. ЛОГИКА ВЫСКАЗЫВАНИЙ 35
истинно, то С должно быть истинным при всех этих интерпретациях.
Если А будет истинным при всех данных интерпретациях, то А дейст-
действительно будет логическим следствием приведенной теории.
При использовании альтернативного семантического метода отыски-
отыскивается модель множества аксиом, для которой А ложно. Если такая мо-
модель существует, то А не будет следствием теории.
Синтаксические методы доказательства
Если применить синтаксический метод доказательства, то необходи-
необходимо найти полное множество правил вывода. Множество правил будет
полным, если оно позволяет вывести любую тождественно истинную ППФ
(т.е. любую тавтологию, которая может быть построена из конечного числа
пропозициональных обозначений). При построении полного множества
правил широко используются два подхода.
Подход, основанный на естественных рассуждениях (см. [26]), тре-
требует использования многих правил вывода, каждое из которых относитель-
относительно легко представить себе интуитивно. К примеру, в число правил вьшода
включаются правила коммутативности, двойного отрицания, дистрибутив-
дистрибутивности, ассоциативности и правило modus ponens (см. разд. 0.3). Если ППФ
является логическим следствием аксиом некоторой теории, то специалист-
логик сможет это продемонстрировать с помощью применения правил
вывода по отношению к аксиомам данной теории. Этот процесс и называ-
называется доказательством ППФ. В системе естественных рассуждений аксиомы
теории называются предпосылками, а результат употребления правил вы-
вывода — заключением. Доказательство состоит из последовательности шагов.
На каждом шаге правило вьшода применяется по отношению к предпосыл-
предпосылкам или к предшествующим заключениям. Заключением, сделанным на
последнем этапе доказательства, будет сама ППФ.
При подходе, в котором употребляются аксиоматические схемы (см.
[71] и [37] ), используется лишь единственное правило вьшода, например,
modus ponens. Помимо этого правила, в системе имеется минимальное ко-
количество аксиоматических схем, которые являются логически тождествен-
тождественно истинными предложными формами. Пример аксиоматической схемы:
(Гр --> ~q) --> (q --> р))
Здесь р и q — пропозициональные переменные ([37], с. 28). Поскольку р
и q обозначают ППФ, то аксиоматическая схема служит обозначением бес-
бесконечного числа аксиом, имеющих такую же синтаксическую форму. Если
ППФ является логическим следствием аксиом теории, то квалифицирован-
квалифицированный специалист-логик сможет доказать это путем искусного применения
аксиоматических схем по отношению к аксиомам данной теории.
2*
36 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Вообще говоря, построение полного множества правил в соответствии
с подходом, при котором применяются аксиоматические схемы, будет
более "элегантным", чем система естественных рассуждений, так как в
первом случае употребляется меньше правил, хотя по этой же причине
разобраться в ходе доказательства может быть сложнее.
Алгоритмическая верификация доказательства
Алгоритм представляет собой систематический метод решения некото-
некоторой задачи. Алгоритм состоит из некоторых исходных формул и правил
преобразования этих формул. Важной отличительно» особенностью алго-
алгоритма является то, что для его использования требуется лишь умение
распознавать строки символов и выполнять действия над этими строками
в соответствии с заданным множеством правил. Из существования полного
множества правил вывода в логике высказываний следует то, что должен
существовать алгоритм для проверки корректности каждого шага доказа-
доказательства. При этом аксиомы теории образуют начальные формулы алгори^
ма, а правила вывода являются правилами преобразований этого алгорит-i
ма. Полное множество правил вывода в логике высказываний называется
исчислением высказываний. В общем случае вопрос: "Представляет ли
собой данная последовательность шагов доказательство того, что требуемая
ППФ является следствием заданных аксиом?" разрешим алгоритмически.
Интересно отметить, что более общий вопрос: "Является ли эта ППФ след-
следствием данных аксиом?" разрешим алгоритмически только тогда, когда
рассматриваемая ППФ действительно является следствием аксиом.
Метаязык и объектный язык
Ученые-логики иногда считают необходимым провести различие между
формальным языком, который они изучают, и тем языком, которым они
пользуются при рассмотрении формального языка. Сам формальный язык
называется объектным языком, а язык, применяемый для его рассмотре-
рассмотрения, называется метаязыком. Объектный язык получил такое название
потому, что в его предложениях могут отражаться логические взаимосвязи
между реальными объектами. Метаязык описывает истинностные значения
обозначений, употребляемых в объектном языке, неформальный смысл
обозначений объектного языка, свойства отдельных предложений объект-
объектного языка, свойства теорий объектного языка и свойства объектного язы-
языка в целом. В данном разделе объектным языком является логика выска-
высказываний. При обсуждении логики высказываний в качестве метаязыка
применяется подмножество естественного языка. Любое предложение,
касающееся свойств любой стороны объектного языка, является предло-
предложением метаязыка. Некоторые примеры предложений метаязыка, касаю-
0.5. ЛОГИКА ПРЕДИКАТОВ 37
щихся высказывания А:
А - истинно.
А — ложно.
Выражение А V ~А логически тождественно истинно.
Неформальный смысл А: "Сегодня идет дождь".
А является логическим следствием теории, определяемой
аксиомами A-4)*).
Полнота и последовательность теории
Про теорию говорят, что она синтаксически последовательна (т.е.
непротиворечива), если из аксиом теории невозможно вывести противоре-
противоречие. К примеру, теория, в которой можно доказать и р, и ~р, непоследова-
непоследовательна. Про теорию говорят, что она полна, если каждую истинную ППФ
можно доказать на основании аксиом этой теории. Последовательность и
полнота являются свойствами теории. Предложение
Теория, определяемая аксиомами A —4), последовательна и полна.
является предложением метаязыка.
0.5. ЛОГИКА ПРЕДИКАТОВ
Атомарные формулы
В логике высказываний элементарным объектом, обладающим значе-
значением истинности, является атомарное высказывание, которое никаким
образом нельзя разделить на компоненты. В логике предикатов элементар-
элементарным объектом, обладающим истинностным значением, является атомарная
формула. Атомарная формула состоит из символического обозначения
предиката и термов, выступающих в роли аргументов этого предиката.
В общем случае обозначение предиката — это имя отношения, существую-
существующего между аргументами. Поскольку сама атомарная формула построена
из других объектов, она обладает гораздо большей выразительной силой,
чем атомарное высказывание в логике высказьшании.
Атомарная формула записывается как обозначение предиката, за ко-
которым в скобках располагаются несколько аргументов. Каждый аргу-
аргумент — это терм. Общий вид атомарной формулы:
P(tl,t2,...,tn)
Здесь Р - обозначение предиката, a tl, t2,.. ., tn - термы.
*) См. с. 34.
38 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Определение понятия "терм"
Терм — это либо константа, либо переменная, либо употребление
функции. "Употребление функции" записывается как символическое обо-
обозначение функции, за которым в скобках располагается список аргументов.
Каждый аргумент сам является термом. Общая форма употребления
функции:
f(tl,t2,...,tn)
Здесь f — обозначение функции, a tl, t2,... , tn — термы.
Словарь символических обозначений логики предикатов
В логике предикатов приняты следующие обозначения: буквы а, Ь, с
обозначают константы, х, у, z обозначают переменные, f, g, h обозначают
функции, а Р, Q, R используются для обозначения предикатов. Этот сло-
словарь можно расширить за счет других обозначений, но предполагаемое ис-
использование каждого вводимого обозначения следует оговаривать явно.
Правильно построенные формулы
Правильно построенная формула (ППФ) получается в результате ком-
комбинирования атомарных формул с логическими соединителями. Правильно
построенная формула определяется следующим образом:
1) атомарная формула — это ППФ;
2) если А и В - ППФ, то ППФ будут и формулы:
ППФ Читается так:
~А не А
А& В АыВ
А V В Аилы В
А > В А имплицирует В
А < > В А тогда и только тогда, когда В
3 х А существует х такой, что А
V х А для любого х, А
Смысл первых шести логических соединителей - точно такой же, как и в
логике высказываний. Кванторы переменных Зх и Vx - новые понятия.
Их смысл обсуждается ниже.
Истинностное значение ППФ
Как и в логике высказываний, истинностное значение ППФ в логике
предикатов зависит от интерпретации. Однако поскольку в атомарных
формулах содержатся термы, интерпретация ППФ в логике предикатов зна-
значительно более сложна, чем интерпретация ППФ в логике высказываний.
Интерпретация ППФ может быть осуществлена только с учетом конкретной
области интерпретации, которая является множеством всех возможных
0.5. ЛОГИКА ПРЕДИКАТОВ
СЕМАНТИКА
39
СИНТАКСИС
Функции, опреде-
определенные в области
интерпретации
Сущности
(область интер-
интерпретации)
Отношения, опреде-
определенные в области
интерпретации
_ Приписывание
Приписывание
Приписывание
Символические
обозначения
функций
Константы,
переменные
Символические
обозначения
предикатов
ППФ, постро-
построенные из
символических
обозначений
Рис. 0.1
значений термов, входящих в ППФ. При традиционном подходе к объясне-
объяснению того, как интерпретация придает смысл ППФ, изложение начинается
с разъяснения синтаксиса ППФ, а затем поясняются возможные смысловые
значения ППФ (см. рис. 0.1). При таком подходе подчеркивается независи-
независимость формальной системы логики предикатов (и самой ППФ) от любой
конкретной интерпретации. Поскольку мы хотим применить логику преди-
предикатов в конечном счете к некоторой конкретной области знаний, был
выбран иной способ объяснения материала. Вначале показывается, как ин-
интерпретация придает смысл ППФ, при этом мы отталкиваемся от смыс-
смыслового значения, а уже потом переходим к возможным ППФ, которые
могут выразить этот смысл.
Построение теории некоторой области знаний
Использование логики предикатов применительно к конкретной об-
области знаний сходно с использованием логики высказываний в том
смысле, что вначале анализируется структура этой области, затем выби-
выбираются обозначения, представляющие особенности данной структуры, а
в заключение при помощи этих обозначений записываются ППФ, опи-
описывающие данную структуру. Как и в логике высказываний, множество
ППФ, описывающих некоторую область знаний, является теорией этой
области знаний, а каждая отдельная ППФ служит аксиомой.
Анализ области знаний
Анализ области знаний выполняется следующим образом. Вначале
выделяется множество значимых сущностей из этой области; данное
множество называется областью интерпретации. Если областью знаний
служит арифметика, то областью интерпретации могут быть натуральные
числа. На следующем этапе определяется, какие функции над элемен-
40 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
тами области интерпретации представляются важными, если только та-
такие функции вообще существуют. Затем идентифицируются значимые
отношения, которые существуют между элементами области интерпре-
интерпретации. В заключение значимые отношения оформляются синтаксически,
т.е. при помощи аксиом.
Определение понятия "функция"
Теперь стоит точно определить, что скрыто за понятиями 'функция'
и "отношение". Функция — это отображение п элементов из области
интерпретации (где п — количество аргументов функции) на один элемеш
этой области. Предположим, к примеру, что областью знаний служит ариф-
арифметика, а областью интерпретации является множество натуральных чи-
чисел. "Умножение" — важная функция для данной области. Функция "умно-
"умножение" имеет два аргумента, как и отображение двух натуральных чисел
на одно натуральное число. Рассмотрим конкретное употребление этой
функции, при котором числа " и " отображаются на число ".
Число " называется значением данного употребления функции "умно-
"умножение".
Другой пример. Пусть область знаний — это родственные отношения
между неким лицом по имени "Боб" и некоторыми другими людьми,
с которыми он общался на семейном сборе. Областью интерпретации
является множество людей:
{ Боб; Джордж, двоюродный брат Боба; Мик, двоюродный брат -V
Боба; Нэнси, подружка Мик а} "!'
"Подружка" — это важная для данной области знаний функция. У функции
"подружка" имеется один аргумент, так же, как и у отображения од-
одного лица на другое. Конкретное употребление этой функции отобра-
отображает "Мик" на "Нэнси". "Мик" - это аргумент, а "Нэиси" - значение
данного употребления функции.
Определение понятия "отношение"
Отношение — это отображение п элементов из области интерпретации
(где п — количество аргументов отношения) на истинностное значение
(т.е. на элемент множества { истина, ложь }). Предположим, что об-
область знаний - арифметика, а область интерпретации - множество нату-
натуральных чисел. "Больше" — это важное для данной области отношение.
Отношение "больше" имеет два аргумента, как и отображение двух нату-
натуральных значений на истинностное значение. Рассмотрим конкретный слу-
случай этого отношения, когда числа " и " отображаются иа значение ложь.
Ложь - это значение отношения "больше" в данном конкретном случае.
В другом конкретном случае данного отношения пара чисел " и "
отображается на значение истина.
0.5. ЛОГИКА ПРЕДИКАТОВ 41
Еще один пример. Предположим, что областью знаний служат сведения
о родственных отношениях людей, участвующих в описанном выше се-
семейном сборе. Отношение "двоюродный брат" имеет важное значение для
этой области знаний. Оно имеет два аргумента, как и отображение двух
имен людей на одно истинностное значение. В конкретном случае данного
отношения имена "Боб" и "Джордж" отображаются на значение истина.
В другом конкретном случае это отношение отображает имена "Джордж"
и "Нэнси" на значение ложь. Если в некотором конкретном случае значе-
значение отношения будет истинным, то говорят, что отношение между аргу-
аргументами соблюдается.
Представление сущностей и отношений
Следующим шагом после установления области интерпретации описы-
описываемой области знаний будет выбор обозначений для представления эле-
элементов области интерпретации. Вначала подбираются обозначения для
констант — а, Ь, с и т.д. Значениями этих констант будут элементы из
области интерпретации. Затем подбираются обозначения для каждой
важной функции, к примеру, f или g. Обратите внимание, что функция
сама по себе не может иметь значения. Значением может обладать только
употребление функции. Функция, представленная некоторым обозначени-
обозначением, определяется семантически путем указания значений различных ее
употреблений (т.е. указанием конкретных случаев отображения п эле-
элементов из области интерпретации, где п — количество аргументов, на один
элемент этой области). В заключение для каждого важного отношения
из области интерпретации подбираются обозначения предикатов, например,
Р и Q. Обозначение предиката как таковое не может иметь значения. Зна-
Значением истинности обладает конкретный случай отношения, представлен-
представленного обозначением предиката. Отношение, представленное обозначением
предиката, определяется семантически путем указания истинностных зна-
значений различных конкретных случаев этого отношения (т.е. точным ука-
указанием того, как данное отношение отображает п элементов об-
области интерпретации, где п — количество аргументов, на истинностное
значение). Конкретный случай отношения представляется атомарной фор-
формулой, построенной на основе выбранных обозначений предикатов, функ-
функций и констант.
Введенные понятия можно проиллюстрировать конкретными приме-
примерами выбора обозначений и определения функций и отношений огшсанным
способом. Пусть область знаний — семейный сбор, а область интерпрета-
интерпретации — множество людей, указанных выше. Вначале выберем обозначения
для констант и припишем им значения, соответствующие элементам об-
области интерпретации.
Значением а является двоюродный брат Боба Джордж.
Значением b является Боб.
Значением с является двоюродный брат Боба Мик.
42 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛСЙ*
Функцию "подружка", имеющую один аргумент, обозначим символом f.
Семантически эта функция определяется путем указания того, что
Значением f(c) является Нэнси.
Символ Р будет обозначать отношение "двоюродный брат", обладающей
двумя аргументами. Семантически это отношение определяется при помор-
поморщи указания того, что Q
'i
Значением Р (а, Ь) является истина. /|
Значением Р(Ь, а) является истина. - f
Значением Р (с, Ь) является истина.
Значением Р(Ь, с) является истина.
Значением Р (а, с) является ложь.
Значением Р (с, а) является ложь. . .
Значением Р (a, f (с)) является ложь.
Значением P(f (с), а) является ложь.
Значением P(b, f (с)) является ложь.
Значением Р (f (с), Ь) является ложь.
Значением Р (с, f(c)) является ложь.
Значением Р (f (с), с) является ложь.
Заметьте, что каждый конкретный случай отношения "двоюродный брат"
представляется атомарной формулой с определенным истинностным зна-
значением. Из приведенных атомарных формул можно строить ППФ, на-
например:
P(a,b)&~P(b,f(c))
Смысл этой ППФ таков: "Джордж является двоюродным братом Боба, а
Боб не является двоюродным братом Нэнси". Поскольку обе атомарные
формулы, входящие в эту ППФ, истинны, то и сама ППФ будет истинна.
Такая ППФ может стать аксиомой в теории данной области знаний. При
построении этой теории попытаемся найти экономичное множество аксиом
(т.е. ППФ, которые истинны), следствием которых явились бы все наши
знания из заданной области.
Выполнив описанные выше действия по выбору обозначений и опреде-
определению функций и отношений и т.д., мы тем самым определили интерпрета-
интерпретацию, при которой ППФ
P(a,b)&~P(b,f(c))
истинна. Теперь легко точно установить, что будет представлять собой ин-
интерпретация ППФ.
0.5. ЛОГИКА ПРЕДИКАТОВ 43
Интерпретация ППФ
Интерпретация ППФ состоит из четырех типов присваиваний.
1) Каждой константе, входящей в ППФ, приписывается некоторый
элемент из области интерпретации (например, значением константы b яв-
является "Боб").
2) Каждой переменной, входящей в ППФ, приписывается элемент из
области интерпретации (это подробно обсуждается ниже).
3) Каждому употреблению функции в ППФ приписывается элемент
из области интерпретации (к примеру, значением f(c) является "Нэнси").
Множество таких присваиваний для некоторой конкретной функции опре-
определяет эту функцию семантически.
4) Каждой атомарной формуле, входящей в состав ППФ, приписывает-
приписывается истинностное значение (скажем, значением Р (а, Ь) является истина).
Множество таких присваиваний для некоторого конкретного отношения
определяет это отношение семантически.
Поскольку теория состоит из множества ППФ, интерпретация теории
заключается точно в таких же четырех видах присваиваний. Важно также
иметь в виду, что для одной и той же области интерпретации могут сущест-
существовать многие интерпретации конкретных ППФ. Например, при одной
интерпретации значением b может быть "Боб", при другой интерпрета-
интерпретации — "Джордж" и т.д. Из приведенного материала должно быть ясно,
что интерпретация ППФ в логике предикатов значительно более сложна,
чем интерпретация ППФ в логике высказываний.
Переменные как термы
Если в атомарной формуле в качестве терма выступает переменная,
то это означает, что на данном месте может присутствовать более чем один
элемент из области интерпретации. К примеру, в ППФ
Р(х,Ь) (•)
значением переменной х является некоторый элемент из области интер-
интерпретации. В представленной форме данной ППФ нельзя приписать истин-
истинностное значение, поскольку неясно, какие значения может принимать
переменная х. В этом случае говорят, что переменная х неквантифици-
рована.
Квантификация переменной
Если в состав ППФ входит переменная, то перед тем, как ППФ будет
можно присваивать истинностные значения, данную переменную необхо-
необходимо явно квантифицироватъ. Для переменных возможны два вида кван-
тификации. Экзистенциальная квантификация показывает, что в области
интерпретации должен существовать по крайней мере один элемент, кото-
который, будучи подставлен на место переменной в ППФ, сделает данную
44 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Таблица 0.12
Символические обозначения кваитификации переменных
Символ Квантификация Смысл
3 х экзистенциальная существует одни х
V х универсальная для всех х
ППФ истинной. Универсальная квантификация показывает, что ППФ бу-
будет истинной при подстановке вместо переменной, входящей в данную
ППФ, любого элемента из области интерпретации. Кванторы переменных
обычно размещаются перед ППФ, содержащей эти переменные. ППФ в этом
случае называют областью действия данного квантора. В табл. 0.12 приве-
приведены обозначения кванторов.
Если воспользоваться квантором существования, то ППФ (*) примет
вид:
Зх Р(х,Ь)
Такой ППФ можно присваивать истинностное значение. В интерпретации,
приведенной выш;, данная ППФ показывает, что "существует некое лицо,
являющееся двоюродным братом Боба", что истинно, так как и Джордж,
и Мик — двоюродные братья Боба.
Если употребить квантор общности, то ППФ (*) будет иметь вид:
Vx P(x,b)
Данной ППФ также можно приписать истинностное значение. В приня-
принятой выше интерпретации эта формула показывает, что утверждения
"х является двоюродным братом Боба для всех х" или "любой человек
является двоюродным братом Боба" ложны, так как значением х может
быть либо "Боб", либо "Нэнси".
Семантические свойства формул
Интерпретация, делающая ППФ истинной, называется моделью этой
ППФ. Говорят, что данная интерпретация удовлетворяет этой ППФ. Ана-
Аналогично такая интерпретация теории, при которой все аксиомы будут
истинными, называется моделью этой теории. Как только что было пока-
показано, пример интерпретации, приведенный выше, является моделью
ППФ:
Зх Р(х, Ь)
0.5. ЛОГИКА ПРЕДИКАТОВ 45
Про ППФ или теорию, которая истинна по крайней мере при одной
интерпретации, говорят, что она удовлетворительна; ППФ или теория,
ложная при всех интерпретациях, называется неудовлетворительной или
непоследовательной. Пример неудовлетворительной ППФ:
Эх P(x,b)& ~P(x, b)
ППФ, истинная при любых возможных интерпретациях, называется тож-
тождественно истинной. Пример такой ППФ:
Эх Р(х, b) V ~P(x, b)
ППФ будет следствием теории, если она истинна во всех моделях этой
теории.
Таблица 0.13
Семантические свойства формулы
ППФ является
Если она
тождественно истинной истинна при всех интерпретациях
("корректной")
следствием теории истинна во всех моделях теории
удовлетворительной истинна по крайней мере при одной интерпрета-
интерпретации
неудовлетворительной не истинна ни при какой интерпретации
Методы доказательства
В логике предикатов существуют методы доказательства того, являет-
является или не является конкретная ППФ следствием аксиом некоторой тео-
теории. Как и в логике высказываний, здесь имеются два метода доказа-
доказательства. Первый из них основывается на семантике используемых ППФ
и аксиом, а второй — на синтаксических действиях над аксиомами.
Простой семантический метод доказательства в логике высказываний
заключается в анализе всех моделей множества аксиом. Если окажется,
что заданная ППФ истинна в каждой из этих моделей, то такая ППФ бу-
будет следствием данной теории. Эквивалентный метод в логике предикатов
требует исследования множества аксиом для всех возможных областей
интерпретации. Однако поскольку количество возможных областей интер-
интерпретации бесконечно, то проверить их все невозможно. Поэтому такой ме-
метод доказательства не годится для логики предикатов.
Альтернативный семантический метод доказательства заключается в поис-
поиске модели множества аксиом для некоторой области интерпретации, при ко-
46 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
торой рассматриваемая ППФ ложна. Если такая интерпретация существует,
то данная ППФ не будет являться следствием теории. К сожалению, тот
факт, что такую интерпретацию обнаружить не удается, вовсе не означает,
что данная ППФ является следствием теории.
Для того чтобы воспользоваться синтаксическим методом доказа-
доказательства, необходимо найти полное множество правил вывода. В разд. 0.4,
в котором излагались сведения о логике высказываний, были упомянуты
два подхода к построению полного множества правил — метод естествен-
естественных рассуждений и метод аксиоматических схем. Метод естественных
рассуждений станет пригодным и для логики предикатов, если допол-
дополнить его правилами вывода, касающимися ППФ, в состав которых вхо-
входят кванторы переменных (см. [26]). Метод аксиоматических схем мож-
можно адаптировать для логики предикатов, если дополнить его аксиомами,
касающимися кванторов переменных (см. [71] или [37]). Полное мно-
множество правил вывода для логики предикатов называется исчислением
предикатов.
Аксиоматическое определение отношения
В примере с семейным сбором мы, с учетом области интерпретации,
тщательно построили семантическое определение отношения "двоюрод-
"двоюродный брат" путем приписывания истинностных значений каждому кон-
конкретному случаю отношения. Было бы желательным, чтобы оказалось
возможным (в качестве составной части процесса построения теории не-
некоторой области знаний) определение предиката при помощи аксиом,
т.е. синтаксически. Такое определение называется аксиоматизацией, или
аксиоматическим определением. Если аксиоматическое определение отно-
отношения окажется возможным, то каждый конкретный случай отношения,
который считается истинным в заданной интерпретации, можно будет вы-
вывести как следствие из аксиом, если воспользоваться синтаксическим ме-
методом доказательства. Другими словами, семантическое определение
отношения окажется выводимым нз его аксиоматического определения
при использовании правил вывода.
Пример: натуральные числа
В следующем примере областью знаний является арифметика, а об-
областью интерпретации — натуральные числа (т.е. положительные целые
числа и ноль). Здесь не будет излагаться подробная теория натуральных
чисел. Читатели, интересующиеся этой теорией, могут обратиться к рабо-
работе Behnke et al. A983 г., с. 71-80) *) . Отметим, что в данном случае имеет-
имеется существенное отличие от примера с семейным сбором — область ин-
*)Эта работа отсутствует в списке литературы. - Примеч. пер.
O.S. ЛОГИКА ПРЕДИКАТОВ 47
терпретации теперь бесконечна. Для построения теории этой области необ-
необходимо разработать представление любого натурального числа в виде
терма. Для этой цели введем константу а, которой приписывается значе-
значение из области интерпретации:
Значением а является 0.
Введем функцию одного аргумента "следующий за", которую обозначим
символом s. Значением употребления этой функции всегда является ее
аргумент, увеличенный на единицу. Например:
Значением s(a) является 1.
Значением s(s(a)) является 2.
Значением s(s(s(a))) является 3.
и т.д.
Рекурсивное определение отношения
Теперь рассмотрим отношение "является натуральным числом", кото-
которое имеет один аргумент. Обозначим это отношение символом N. Отноше-
Отношение, имеющее один аргумент, называется также свойством. В данном слу-
случае отношение можно определить при помощи следующих аксиом:
N(a) A)
Vx N(x)-*N(s(x)) B)
Аксиома A) утверждает, что а — это натуральное число. Аксиома B) гла-
гласит, что число, следующее за любым натуральным числом х, также являет-
является натуральным числом.
Если использовать совместно данные аксиомы и полное множество
правил вывода логики предикатов, то окажется возможным доказать
синтаксически, что отношение, обозначенное символом N, соблюдается
для любого терма, который может быть построен при помощи симво-
символа а, обозначающего константу, и символа s, обозначающего функцию.
Определение N называется рекурсивным, поскольку в аксиоме B) со-
соблюдение отношения в одном конкретном случае (N(s(x))) зависит от
соблюдения этого отношения в другом конкретном случае (т.е. N(x)).
Более подробно рекурсия обсуждается в разд. 1.6.
Рекурсивная перечислимость
Аксиомы A) н B) дают конструктивное определение множества
натуральных чисел в том смысле, что любое натуральное число может
быть построено путем повторяющегося применения к аксиомам правил
вывода. Комбинация полного множества правил вывода и двух данных
аксиом описывает рекурсивный алгоритм. Здесь описан именно алгоритм,
так как описание состоит из исходных формул и правил преобразования
этих формул. Алгоритм рекурсивен, потому что сами аксиомы рекурсив-
48 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛО§|
ны. Говорят, что множество натуральных чисел рекурсивно перечислим^
поскольку оно может быть образовано с помощью рекурсивного алгорит-
алгоритма. В более общем случае множество термов (натуральных чисел или иных
объектов), обладающих некоторым свойством, будет рекурсивно перечис-
перечислимым, если это множество может быть образовано посредством приме-
применения рекурсивного алгоритма.
"Больше"
Другим интересным примером отношения из области арифметики
может служить отношение "больше", которое можно определить аксио»
матически. Данное отношение, имеющее два аргумента, обозначим симвсн
лами GT (от английских слов greater than). Семантически данное отноше-
отношение можно определить следующим образом:
Значением GT(s(a), а) является истина.
Значением GT(s(s(a)), а) является истина.- '•
и т.д.
Значением GT(s(s(a)), s(a)) является истина.
Значением GT(s(s(s(a))), s(a)) является истина.
и т.д.
Значением GT(a, а) является ложь.
Значением GT(a, s(a)) является ложь.
Значением GT(s(a), s(a)) является ложь.
и т.д.
Аксиоматическое определение данного отношения, отражающее смысл
приведенного семантического определения, будет иметь вид:
Vx GT(s(x),x) A)
Vx Vy GT(x, у) -> GT(s(x), у) B)
Vx ~GT(x,s(x)) C)
Vx Vy ~GT(x, y) -* ~GT(x, s(y)) D)
Аксиома A) утверждает, что для каждого натурального числа х число,
следующее за ним, будет больше, чем х. Аксиома B) гласит, что для любых
чисел х и у, если х больше у, то и число, следующее за х, будет больше у.
Аксиома C) утверждает, что для любого числа х число х не больше, чем
число, следующее за ним. Аксиома D) гласит, что для любых чисел х и у,
если х не больше, чем у, то х также не больше, чем число, следующее за у.
Эти аксиомы позволяют доказать синтаксически, является ли какой-
либо конкретный случай отношения "больше" истинным или ложным.
Данное определение рекурсивно, так как в аксиоме B) соблюдение одно-
одного конкретного отношения (скажем, GT(s(x), у)) зависит от соблюдения
другого конкретного отношения (т.е. GT(x, у)).
0.5 ЛОГИКА ПРЕДИКАТОВ 49
Разрешимость свойств
Математики, исследовавшие свойства чисел в начале нынешнего столе-
столетия, приняли аксиоматический метод определения свойств чисел как сред-
средство, позволяющее не полагаться на интуицию. Однако пользование аксио-
аксиоматическим методом привело (в качестве "побочного эффекта") к поста-
постановке более фундаментальной проблемы: существуют некоторые свойства
чисел, которые одновременно истинны и неразрешимы (т.е. недоказуемы
при использовании конечного множества аксиом и полного множества
правил вывода).
Рекурсивная разрешимость
Исследование проблемы разрешимости свойств принесло следующие
результаты. Отношение или свойство, определенное на бесконечной об-
области интерпретации, которой, к примеру, являются натуральные числа,
представимо в теории первого порядка только в том случае, если оно ре-
рекурсивно. Отношение или свойство разрешимо, если существует рекурсив-
рекурсивно перечислимое множество термов, обладающих этим свойством, т.е. ес-
если данное множество может быть образовано при помощи рекурсивного
алгоритма за конечное число шагов. Вспомним, что теория называется
полной, если все известные истинные сведения из области знаний, описы-
описываемой этой теорией, являются следствием аксиом теории. Ввиду того,
что свойства чисел одновременно и истинны, и неразрешимы, никакая
аксиоматическая теория арифметики не может быть полной.
Рекурсивная вычислимость
Изучение природы рекурсивной вычислимости позволяет предполо-
предположить возможность применения процедуры, которая будет механически
выполняться человеком или компьютером и обладать способностью до-
доказать то, что заданная ППФ является следствием множества аксиом,
если эта ППФ в действительности является следствием этого множества
аксиом. Если бы такая процедура существовала, то рекурсивная разреши-
разрешимость вопроса: "Является ли заданная ППФ следствием данных аксиом?"
сводилась бы к вопросу о рекурсивной вычислимости с помощью упомя-
упомянутой процедуры. Тьюринг и ряд других ученых исследовали практичес-
практические аспекты рекурсивной вычислимости. "Машина Тьюринга" — зто абст-
абстрактная система, позволяющая судить о вычислимости любого рекурсив-
рекурсивного алгоритма. Сходным образом язык логического программирования,
например, Пролог, позволяет определить при помощи вычислений, являет-
является ли заданная ППФ следствием аксиом некоторой теории.
50 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
0.6. ОТ ФОРМАЛЬНОЙ ЛОГИКИ - К ЛОГИЧЕСКОМУ ПРОГРАММИРОВАНИЮ
Автоматизация процедур доказательства
После того, как была открыта вычислимость логических следствий
в абстрактном смысле, возникло естественное желание автоматизиро-
автоматизировать процесс доказательства при помощи компьютера. Однако, как отме-
отмечает Робинсон, "задача фактического выполнения вычислений при помощи
процедуры, первоначально предназначенной лишь для того, чтобы провести
доказательство "существования", . . . оказалась очень сложной" ([92,
с. 292]). Полная логика предикатов — это язык, обладающий богатыми
выразительными средствами. Если попытаться в общем виде реализовать
на компьютере процедуры доказательства, разработанные для исчисления
предикатов, то возникнет проблема комбинаторного роста числа вариан-
вариантов. В конце 50-х—начале 60-х гг. ученые приступили к поиску таких прием-
приемлемых с точки зрения объема вычислений методов реализации процедур
доказательства, которые в максимально возможной степени сохранили бы
выразительную силу логики предикатов первого порядка. У специалистов
зародилась мечта о создании на практике универсальной машины — "ре-
"решателя задач", которую задумал еще Лейбниц.
В конце 50-х годов Гилмор, Дэвис, Патнзм и Правиц начали работу
по созданию автоматизированного метода доказательства через опровер-
опровержение. За основу был взят метод, разработанный Хербрандом в 30-е го-
годы (см. [100, 101]). Основываясь на работе Правица, Робинсон создал
правило вывода, которое он назвал резолюцией. Это правило пригодно для
выполнения вывода машиной [91]. Первоначально попытки создания
алгоритма решения задач, базирующегося на резолюции, оказывались
успешными только для очень небольших задач. Лавленд, Ковальски и Куэ-
нер усовершенствовали такие алгоритмы, разработав метод устранения
моделей [63] и метод селектирующей функции [57]. В начале 70-х гг.
Кольмерор и Руссель воспользовались результатами этих работ при созда-
создании языка, базирующегося на правиле резолюции. Этот язык они назвали
Пролог — Программирование при помощи ЛОГики [93].
В следующих разделах описываются интерпретации Хербранда, фра-
фразовая форма логики и правило резолюции. Там показано, как из исчисле-
исчисления предикатов первого порядка развилось логическое программирова-
программирование, а также объясняется процедура доказательства через опровержение.
Процедуры опровержения
Из определений тождественной истинности и непоследовательности
(см. разд. 0.4) следует, что ППФ будет тождественно инстинной тогда
и только тогда, когда добавление в теорию отрицания данной ППФ превра-
превратит эту теорию в непоследовательную. С позиций семантики теория будет
непоследовательной, если не существует интерпретации, удовлетворяющей
|б. ОТ ФОРМАЛЬНОЙ ЛОГИКИ - К ЛОГИЧЕСКОМУ ПРОГРАММИРОВАНИЮ 51
¦сем аксиомам этой теории. С позиций синтаксиса теория будет непосле-
непоследовательной, если окажется возможным вывести из нее противоречие
вида
А&~А
Процедура опровержения — это особый вид процедуры доказательства,
при котором используется описанное соотношение между тождественной
истинностью и непоследовательностью. Метод, который применяется в про-
процедуре опровержения, заключается в следующем. Для доказательства
того, что ППФ является следствием аксиом теории, необходимо показать,
что будет возможным вывести противоречие, когда к теории добавляется
Этрицание данной ППФ.
Для того чтобы дать семантическое объяснение процедуры доказа-
гельства через опровержение, воспользуемся особой областью интерпре-
интерпретации, называемой миром Хербранда. Мир Хербранда обладает следую-
следующим свойством: ППФ будет следствием аксиом теории, если отсутствует
интерпретация мира Хербранда, при которой одновременно и отрицание
}той ППФ, и все аксиомы теории были бы истинными. Тем самым для
(семантического) понимания того, почему некоторая ППФ является след-
:твием теории, необходимо лишь рассмотреть все интерпретации мира
Хербранда.
Мир Хербранда
Мир Хербранда для некоторой теории определяется через обозначе-
обозначения, используемые в этой теории. Основной терм (ground term) — это
1ибо обозначение константы, либо употребление функции, все аргументы
которой являются основными термами. Мир Хербранда для некоторой
теории состоит из всех основных термов, которые могут быть построены
на основе обозначений, используемых в этой теории.
Рассмотрим в качестве примера теорию первого порядка, построенную
только из следующих символических обозначений: символы, обозначаю-
дие константы, — a, b и с; символы, обозначающие переменные, — х, у и z;
;имволы, обозначающие предикаты, — Р (с одним аргументом) и Q (с дву-
двумя аргументами). Символы, обозначающие функции, в данном примере
)тсутствуют. Поскольку здесь нет обозначений функций, мир Хербранда
1ля данной теории состоит всего лишь из трех символов, обозначающих
<онстанты:
a b с
Основание Хербранда
Основная атомарная формула (ground atomic formula) — это атомар-
1ая формула, не содержащая переменных в качестве аргументов, т.е. все
1ргументы являются основными термами. Скажем, в рассматриваемом
1римере теории Q(a. b) - это основная атомарная формула, a Q(x, у) та-
сой формулой не является. Основание Хербранда для теории — это мно-
P(a)
Q(a,
Q(b,
Q(c,
a)
a)
a)
P(b)
Q(a,
0(b,
Q(c,
b)
b)
b)
52 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
жество всех основных атомарных формул, которые можно построить из
обозначений, используемых в теории. Для рассматриваемого примера
теории полный вид основания Хербранда будет таким:
Р(с)
Q(a,c)
Q(b, с)
Q(c, с)
Хербрандовские интерпретации
Мир Хербранда - это область интерпретации для хербрандовской
интерпретации. В хербрандовской интерпретации теории значением каждо-
каждого основного терма является он сам. Иными словами,
Значением а является а
Значением b является b ¦ •
и т.д. • .[.
В любой конкретной хербрандовской интерпретации каждая основная
атомарная формула в основании Хербранда означает либо истину, либо
ложь. Для заданной теории существует только такое количество хербран-
довских интерпретаций, сколько имеется возможных вариантов приписы-
приписывания истинностных значений атомарным формулам, входящим в основа-
основание Хербранда этой теории.
Одна из хербрандовских интерпретаций основания Хербранда, приве-
приведенного выше, имеет вид:
Значением Р(а) является истина ...
Значением Р(Ь) является истина -.
Значением Р (с) является истина
Значением Q(a, а) является ложь •.
Значением Q(a, b) является истина
Значением Q(a, с) является ложь
Значением Q(b, а) является ложь
Значением Q(b, b) является ложь
Значением Q(b, с) является истина
Значением Q(c, а) является ложь
Значением Q(c, b) является ложь
Значением Q(c, с) является ложь .
В основание Хербранда входят двенадцать формул, поэтому в рассмат-
рассматриваемом примере существуют 212 = 4096 возможных хербрандовских
интерпретаций.
Хербрандовская модель теории — это такая хербрандовская интерпре-
интерпретация, при которой каждая аксиома теории истинна.
0.6. ОТ ФОРМАЛЬНОЙ ЛОГИКИ - К ЛОГИЧЕСКОМУ ПРОГРАММИРОВАНИЮ 53
Полезные свойства хербрандовских интерпретаций
Хербрандовские интерпретации обладают полезным свойством: на
уровне истинностных значений атомарных высказываний, присутствующих
в конкретной теории, всегда существует хербрандовская интерпретация,
соответствующая любой возможной нехербрандовской интерпретации.
(Это свойство не имеет силы на уровне значений термов, используемых
в теории. В нехербрандовской интерпретации значением константы, к при-
примеру, Ь, будет некоторый элемент области интерпретации, скажем, "Боб".
В хербрандовской же интерпретации значением константы, например,
той же Ь, всегда будет она сама.) Данное свойство хербрандовских интер-
интерпретаций позволяет сделать следующее заключение: если ППФ будет истин-
истинной во всех хербрандовских моделях теории, то она будет истинна и во
всех моделях этой теории для всех возможных областей интерпретации и,
следовательно, будет следствием данной теории.
Таким образом, с позиций семантики процедуру опровержения мож-
можно представить себе так.
Для того, чтобы определить, является ли ППФ следствием теории,
нужно взять отрицание этой ППФ.
Надо попытаться найти хербрандовскую модель теории, при которой
отрицание ППФ будет истинным.
Если такая модель существует, то рассматриваемая ППФ не может
быть следствием данной теории.
Если же такой модели не существует, то ППФ является следствием
теории.
Фразовая форма
Фразовая форма логики предикатов — это способ записи формул,
при котором употребляются только соединители &, V и ~. Литерал — это
позитивная или негативная атомарная формула. Каждая фраза — это мно-
множество литералов, соединенных символом V. Негативные литералы разме-
размещаются в конце каждой фразы, а позитивные - в начале. Схематический
вид фразы:
Р1 V Р2 V . .. Pn VN1 V N2 V . . . Nn
Здесь Р1 . . . Рп — позитивные литералы, а N1 ... Nn — негативные лите-
литералы.
Фразу можно рассматривать как обобщение понятия импликации
(см. разд. 0.3) . Если А и В — атомарные формулы, то формула
А --> В
может также быть записана как
~А V В
54 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Поскольку ~А — негативно, а В — позитивно, то фразовая форма будет
иметь вид:
В V "А
Альтернативные заключения и необходимые условия
Все позитивные атомарные формулы, входящие во фразу, являются
альтернативными заключениями, а все негативные атомарные формулы —
необходимыми условиями. К примеру, если С, D, Е и F — атомарные фор-
формулы, то фраза
CVD V~E V ~F
гласит, что С или D будут истинными, если одновременно и Е, и F истинны.
(Чтобы разобраться в этой трактовке формулы, полезно вспомнить пра-
правила Де Моргана, в которых утверждается, что ~Е V ~F эквивалентно
~(E&F).)
Простейшая фраза содержит только один литерал, позитивныйили не-
негативный. Если a, b и с — константы, a Q. — предикат с двумя аргумента-
аргументами, то
Q(a, b)
— это фраза, в которой утверждается, что Q(a, b) безусловно истинно.
Фраза
~Q(b,c)
означает, что Q(b, с) безусловно ложно. Теория записывается в виде мно-
множества фраз. Считается, что эти фразы неявно соединены между собой
символом &..
Форма записи с обратной стрелкой
Фразы можно записывать с использованием обратной стрелки импли-
импликации, стоящей между позитивными и негативными литералами. Литера-
Литералы, расположенные по разные стороны от стрелки, соединяются запятыми.
Обратная стрелка читается как "имплицируется". Так,
С, D < Е, F
означает то же самое, что и
С V D V ~Е V ~F
Фразы Хорна
Фраза Хорна — это фраза, содержащая только один позитивный лите-
литерал. Фраза из предыдущего примера не является фразой Хорна, так как
в ней имеются два позитивных литерала. Однако фраза
С V ~Е V ~F V ~G
0.6. ОТ ФОРМАЛЬНОЙ ЛОГИКИ - К ЛОГИЧЕСКОМУ ПРОГРАММИРОВАНИЮ 55
является фразой Хорна. Если воспользоваться обратной стрелкой, то эта
фраза примет вид
С < E,F,G
Резолюция
Робинсон пришел к заключению, что правила вывода, которые следует
применять при автоматизации процесса доказательства при помощи ком-
компьютера, не обязательно должны совпадать с правилами вывода, исполь-
используемыми человеком. Он обнаружил, что общепринятые правила вывода,
например, правило modus ponens, специально сделаны "слабыми", чтобы
человек смог интуитивно проследить за каждым шагом процедуры дока-
доказательства. Робинсон открыл более сильное правило вывода, которое он
назвал резолюцией (или правилом резолюции). Это правило трудно под-
поддается восприятию человеком, но эффективно реализуется на компьютере.
(Правило резолюции сходно с дизъюнктивным правилом силлогизма,
см. табл. 0.2).
Правило резолюции оказывается особенно привлекательным для целей
вычислений, так как оно само по себе является полным множеством пра-
правил вывода для фразовой формы логики предикатов. Иными словами,
при использовании одного лишь правила резолюции возможно вывести лю-
любое следствие из множества аксиом, представленных во фразовой форме.
Правило резолюции
Правило резолюции действует следующим образом. Две фразы могут
быть резольвированы друг с другом, если одна из них содержит позитив-
позитивный литерал, а другая — соответствующий негативный литерал с одним
и тем же обозначением предиката и одинаковым количеством аргументов,
и если аргументы обоих литералов могут быть унифицированы (т.е. согла-
согласованы) друг с другом. Рассмотрим теорию, состоящую лз двух фраз:
!Р(а) V ~Q(b, с) @
Q(b,c) V ~R(b,c) B)
Поскольку во фразе A) содержится негативный литерал ~Q(b, с), а во
фразе B) - соответствующий позитивный литерал Q(b, с) и аргументы
обоих литералов могут быть унифицированы (т.е. b унифицируется с Ь,
а с унифицируется с с), то фраза A) может быть резольвирована с фра-
фразой B). В результате этого получится фраза C), которая называется
резольвентой. Она становится новой фразой теории:
Р(а) V ~R(b, с) C)
56 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
После выполнения данной резолюции при последующих резолюциях мож-
можно воспользоваться любой из фраз A), B) и C).
Фразы D) и E) не резольвируются друг с другом, так как аргументы
литералов Q не поддаются унификации:
Р(а) V~Q(b,c) D)
Q(c, с) V ~R(b,c) E)
Унификация переменных
Во фразовой форме не употребляется явная квантификация перемен-
переменных. Неявно, однако, все переменные квалифицированы кванторами су-
существования. Так, во фразе
Q(x,y) V ~R(x,y) " •
подразумевается наличие кванторов:
VxVy(Q(x,y) V ~R(x,y))
Если в качестве аргумента выступает переменная, то она унифицируема
с любой константой. Если в одной и той же фразе переменная встречается
более одного раза и эта переменная в процессе резолюции унифицируется
с константой, то резольвента будет содержать данную константу на тех
местах, где рассматриваемая переменная располагалась в исходной фразе.
К примеру, фразы
Р(а) V ~Q(a,b) F)
Q(x,y)V~R(x,y) G)
резольвируемы, поскольку аргументы литерала Q унифицируются. При
этом переменная х унифицируется с константой а, а переменная у — с
константой Ь. Обратите внимание, что во фразе (8), т.е. в резольвенте
P(a)V~R(a,b) (8)
переменные, служившие аргументами R во фразе G), теперь заменены на
константы.
Пустая фраза
Рассмотрим две фразы:
Р(а) (9)
~Р(а) A0)
0.6. ОТ ФОРМАЛЬНОЙ ЛОГИКИ - К ЛОГИЧЕСКОМУ ПРОГРАММИРОВАНИЮ 57
фраза (9) — это заключение без условий, а фраза A0) — это условие без
заключения. Присутствие фраз (9) и A0) в одной теории является проти-
противоречием. Если фразы (9) и A0) резольвируются друг с другом, то по-
получающаяся резольвента называется пустой фразой. Если при резолюции
двух фраз, входящих в состав теории, получается пустая фраза, то эта
теория должна быть непоследовательной. С позиций семантики возмож-
возможность выведения пустой фразы означает, что нельзя построить хербран-
довскую модель этой теории.
Алгоритм, основанный на резолюции
Основная проблема состоит в доказательстве того, является ли неко-
некоторая фраза следствием теории или нет. Применение процедуры опровер-
опровержения (см. выше) как основного метода доказательства упрощает эту
задачу, сводя ее к необходимости определения того, является ли теория
последовательной или непоследовательной. Для того чтобы автоматизиро-
автоматизировать процесс поиска решения, было бы хорошо найти эффективный алго-
алгоритм, основывающийся на правиле резолюции, который позволял бы
обнаруживать противоречивость множества фраз.
Предположим, что теория выражена во фразовой форме. Все фразы
этой теории, за исключением одной, совместимы друг с другом. Наличие
этой искомой фразы превращает всю теорию в непоследовательную. Пред-
Представим себе, что существует некоторая активная сила (человек или ма-
машина), которая по случайному закону применяет правило резолюции по
отношению к фразам теории. После каждого выполнения резолюции по-
получающаяся резольвента добавляется в теорию. Если будет сгенерирована
пустая фраза, то это будет означать, что теория непоследовательна, и тогда
эта активная сила прекратит свои действия. Поскольку рассматриваемая
теория действительно является непоследовательной, активная сила, рано
или поздно, сгенерирует пустую фразу и тем самым обнаружит непосле-
непоследовательность теории. Однако многие из резолюций будут либо избыточ-
избыточными, либо не относящимися к искомой фразе. Для создания эффектив-
эффективного алгоритма обнаружения непоследовательности теории необходимо
наложить ограничения на данный процесс и направить его активность на
участки, которые с наибольшей вероятностью могут привести к появле-
появлению пустой фразы.
При использовании правила резолюции применима более чем одна
стратегия решения задач. В оставшейся части данного раздела будет рас-
рассмотрена нисходящая {или обратная) стратегия. В этой стратегии ставится
Цель обнаружить, является ли единственная фраза С следствием существую-
существующего множества фраз Т. Предполагается, что множество фраз Т является
непротиворечивым. Алгоритм работает следующим образом. Вначале к
58 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
существующему множеству фраз добавляется отрицание проверяемой
фразы ~С. При этом образуется новое множество фраз Т1, состоящее из
множества Т плюс фраза ~С. Если агоритм позволит вывести пустую
фразу из Т', то Т' будет непоследовательным из-за присутствия фразы ~С,
и поэтому С должно являться следствием Т. Этот процесс можно проиллю-
проиллюстрировать примером.
Пример резолюции нисходящим методом
Пусть имеется множество фраз
P(a)V~Q(a,b) F)
Q(x,y)V~R(x,y) G)
S(b) A1)
R(a,b) . . - A2)
Необходимо выяснить, является ли фраза
Р(>) A3)
следствием существующего множества фраз. На первом шаге добавим
к остальным фразам отрицание фразы Р(а). В результате этого получим:
P(a)V~Q(a,b) F)
Q(x,y)V~R(x,y) G)
S(b) A1)
R(a,b) A2)
~P(a) A4)
Действие данного алгоритма резолюции будет сфокусировано на след-
следствиях добавления фразы A4) к существующему множеству фраз. Это
достигается при помощи двух правил:
1) в первой выполняемой резолюции следует использовать только что
добавленное отрицание фразы (т.е. фразу A4));
2) в каждой последующей резолюции должна участвовать резольвента
предыдущей резолюции (это предотвращает бесцельное "блуждание" ал-
алгоритма) .
В соответствии с первым правилом в первой резолюции должна принимать
участие фраза A4). Она резольвируется с фразой F), в результате чего
получится:
~Q(a,b) A5)
Согласно правилу 2) в следующей резолюции должна участвовать фраза
0.7. РАЗВИТИЕ ЯЗЫКА ПРОЛОГ 59
A5). Эта фраза резольвируется с фразой G). Результатом будет фраза
~R(a,b) ^ A6)
(Обратите внимание, что все переменные из исходной для R формулы за-
заменены во фразе A6) на константы.) Фраза A6) резольвируется с фра-
фразой A2), что приводит к образованию пустой фразы. Это означает, что
обнаружено противоречие. Ввиду того, что добавление ~Р(а) к сущест-
существующему множеству фраз приводит к противоречию, Р (а) является след-
следствием множества фраз.
Стратегия решения задач
Описанная только что стратегия решения задач характеризуется сле-
следующими свойствами. Эта стратегия является нисходящей, так как она
начинает процесс решения с отрицания заключения (т.е. с фразы ~Р(а)),
а далее в процессе решения используются остальные фразы теории, что
продолжается до тех пор, пока не будет выведена пустая фраза. Данная
стратегия решения называется стратегией поиска "сначала вглубь", по-
поскольку результат последней резолюции всегда используется в следующей
за ней резолюции.
0.7. РАЗВИТИЕ ЯЗЫКА ПРОЛОГ
Развитие языка Пролог
В течение 70-х гг. Пролог прошел путь развития от интересующего
лишь узких специалистов экспериментального языка, созданного евро-
европейскими учеными, до одного из ведущих языков программирования, ши-
широко используемого во всем мире. Можно отметить два важных аспекта,
способствовавших совершенствованию языка Пролог в этот период. Во-пер-
Во-первых, в результате работ по теории логического программирования был
создан концептуальный аппарат, необходимый для эффективного приме-
применения языка. Во-вторых, разработка улучшенных стратегий реализации язы-
языка привела к появлению эффективно функционирующих версий Пролога.
Теория
Очень важную роль в развитии теории логического программирования
сыграла работа Ковальски. Он первым предложил метод, в соответствии
с которым логический язык можно было бы использовать как язык про-
программирования (см. [54]). Совместно с ван Эмденом он предложил два
альтернативных подхода к прочтению текстов логических программ - про-
процедурный и декларативный подходы ([116], эта работа обсуждается далее
в разд. 0.8). С тех пор этот автор более подробно изложил свои научные
взгляды по данной теме. Особое внимание привлекает его работа [55].
Его идеи во многом определили направление исследований по логическому
60
ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
программированию в течение последних нескольких лет. Важный вклад
в теорию логического программирования внесли Эпт [3], Кларк (Clark
[1977])*) иБоуэн [6].
Таблица 0.14
Основные вехи эволюции Пролога
1879 г. Фреже публикует работу "Концептуальный язык"
1965 г. Дж.Э. Робинсон "Машинно-ориентированная логика, основанная на
принципе резолюции"
1968 г. Лавленд "Автоматическое доказательство теорем путем устранения
моделей"
1971 г. Ковальски и Куэнер "Линейный отбор при помощи функции резо-
резолюции"
1973 г. Кольмерор в Марселе написал первую версию интерпретатора Проло-
Пролога, пользуясь языком Фортран [^З]
1974 г. Ковальски "Логика предикатов как язык программирования-"
1977 г. Уоррен и Перейра из Эдинбургского университета создали интер-
претатор/компилятор языка Пролог для ЭВМ DEC-10
1980 г. В Империал Колледже разработан интерпретатор языка микро-
Пролог для персональных ЭВМ [20]
1981 г. Проект создания ЭВМ пятого поколения, основанной на методах
логического программирования - институт ICOT, Япония [74|
Реализация языка
Первая версия интерпретатора языка Пролог была написана Кольмеро-
ром и Русселем иа Фортране и работала крайне медленно. В 1977 г. Уоррен
и Перейра завершили работу над интерпретатором/компилятором языка
Пролог для ЭВМ DEC-10. Они показали, что при решении крупных задач
Пролог может быть столь же эффективен, как и Лисп [111]. Алгоритм,
использованный при реализации языка Пролог на ЭВМ DEC-10, теперь
известен как "машина Уоррена". Этот алгоритм послужил прототипом для
многих последующих реализаций Пролога [105]. В 1980 г. Кларк и Мак-
кейб закончили работу по созданию версии языка Пролог для микро-
микрокомпьютеров. Теперь эта версия используется в качестве первоначального
языка программирования в колледжах с неполным курсом обучения в
Великобритании ([20], [32]). Перейра написал на языке Си интерпретатор
языка Пролог для операционной системы UNIX, а теперь имеется и не-
несколько других версий языка Пролог для системы UNIX [83]. Кан и ряд
*) Этой работы нет в списке литературы. — Примеч. пер.
0.7. РАЗВИТИЕ ЯЗЫКА ПРОЛОГ 61
других специалистов реализовали версию языка Пролог на Лисп-машинах
[48]. Различные версии языка Пролог, предлагаемые на рынке про-
программных средств, детально обсуждаются в приложении IV.
ICOT
В 1981 г. Японское министерство международной торговли и промыш-
промышленности объявило о создании специальной исследовательской организа-
организации — Института по разработке методов создания компьютеров нового
поколения (ICOT), призванного вести работу над тем, что было названо ме-
методологией создания компьютеров пятого поколения [74]. К удивлению
многих американских специалистов по искусственному интеллекту, в ка-
качестве основной методологии разработки программных средств для проек-
проекта ЭВМ пятого поколения было избрано логическое программирование.
Целью данного проекта является создание систем обработки информации,
базирующихся на знаниях. Предполагается, что будут разработаны системы,
базирующиеся на знаниях, которые будут обладать возможностью общения
с пользователями при помощи естественного языка или графических
средств и которые будут помогать пользователям в решении некоторых
классов задач высокого уровня, предоставляя им экспертные консульта-
консультации. Полезный эффект от таких систем будет заключаться в том, что в
распоряжение широких слоев общества будут предоставлены мощные вы-
вычислительные ресурсы и что возрастет производительность труда в ряде
отраслей промышленности, в которых сейчас она традиционно низка.
Логические выводы в секунду
Проект создания аппаратных средств ЭВМ пятого поколения вызвал
появление нового параметра, позволяющего измерять скорость работы раз-
различных версий Пролога, — числа логических выводов в секунду (лвс)*).
Одной из целей ICOT является построение логически программируемых
машин, работающих в диапазоне скоростей от 1000 до ЮОООКлвс. Пока
наблюдается значительный разрыв по производительности между этой
Целью и нынешними версиями Пролога. Для сравнения можно привести
следующие данные. Исходная версия компилятора языка Пролог для ЭВМ
DEC-10 позволяла создавать программы, работающие со скоростью 10 К
лвс. Улучшения, внесенные в этот компилятор, и применение аппаратных
средств с более высоким быстродействием (DEC-2060) дали возможность
довести скорость выполнения программы до 35 — 40 К лвс. Для сравнения
отметим, что интерпретатор микро-Пролога работает со скоростью около
200 лвс на ЭВМ с микропроцессором Z-80, а интерпретатор СиПролога
работает на ЭВМ VAX 11/780 со скоростью 1,5 К лвс. Персональная машина
*) По-английски этот параметр обозначается как LIPS - Logical inferences per
second. - Примеч. пер.
62 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
последовательного вывода, созданная в ICOT, — это компьютер со спе-
специализированным процессором, архитектура которого оптимизирована
в соответствии с требованиями языка Пролог. Она работает со скоростью
20—30 К лвс. Последний компилятор языка Пролог (Квинтус Пролог),
написанный Уорреном, генерирует код, работающий со скоростью 50 К лвс
на рабочей станции, построенной на основе микропроцессора [97]. В на-
настоящее время ходят слухи о создании в США и Японии эксперименталь-
экспериментальных машин, работающих со скоростью более 600 К лвс.
Другие языки
Следует, однако, заметить, что логическое программирование не начи-
начиналось с современных версий языка Пролог и не закончит свое развитие
ими. Были изобретены и иные языки логического программирования,
к примеру, DUC [70], ESP [16] и HCPRVR [102], а также языки-оболочки
(shells), базирующиеся на логическом программировании, скажем, APES
[38]. Сейчас одновременно ведется несколько исследовательских работ
по созданию языка логического программирования, дающего, возмож-
возможность реализовать преимущества параллельной архитектуры ЭВМ. К числу
таких разрабатываемых языков относятся Парлог [18], Параллельный
Пролог [96] и KL1 института ICOT.
Особенности языка Пролог
В языке Пролог сочетается использование нескольких важных кон-
концепций, к числу которых относятся:
1) применение фраз Хорна для представления знаний;
2) дескриптивный стиль программирования;
¦С 3) как декларативная, так и процедурная семантика;
4) возможность чередовать программный текст метауровня с текстом
объектного уровня.
Эти концепции будут введены в оставшейся части данной главы, а в осталь-
остальных главах книги будет показано их практическое употребление.
0.8. СИНТАКСИС ЯЗЫКА ПРОЛОГ
Перед тем как перейти к изложению нового материала, было бы полез-
полезным рассмотреть, как логические фразы Хорна записываются на языке
Пролог. Приводимые ниже примеры тривиальны, их предназначение —
продемонстрировать основные составные части Пролог-программы.
Во фразах Хорна после единственного заключения следуют ноль или
более условий. На Прологе это записывается следующим образом:
заключение :—
условие1,
условие2,. . .
условней.
Ц>.8. СИНТАКСИС ЯЗЫКА ПРОЛОГ 63
Здесь ":—" читается как "если", а "," читается как "и", поэтому всю фразу
можно прочесть так:
Заключение будет истинным, если
условие! и условие2 и ... условиеН
будут истинными.
Главным компонентом интерпретатора языка Пролог является уни-
универсальный механизм решения задач, принцип действия которого основан
на правиле резолюции. Для того чтобы воспользоваться этим механизмом,
программист должен четко описать задачу при помощи фраз Хорна, выра-
выраженных на языке Пролог. В каждой фразе формулируется некоторое отно-
отношение между термами. Терм — это обозначение, представляющее некото-
некоторую сущность из исследуемого мира. Для того чтобы привести в действие
данный механизм решения задач, программист должен написать запрос,
согласно которому будет необходимо выяснить, является ли конкретная
атомарная формула следствием текущего множества фраз, представленных
в программе.
Пример Пролог-программы
Простейшей фразой Хорна может служить некоторый факт, состоящий
из заключения, за которым не следуют никакие условия, например:
хэкер(джои).
Это можно прочесть так:
Джон — хэкер *).
Правило - это иная форма фразы Хорна, показывающая зависимость
одного факта от других. К примеру, фразу
получать_по_шее (джон) :— хэкер (джон).
можно прочитать так:
Джон получает по шее, если он хэкер.
Обратите внимание на направление вывода, подразумеваемое этим прави-
правилом. Если уже известно, что Джон — хэкер, то правило дает дополнительные
знания о том, что Джон получает по шее. Слово « джон » - это обозначение
константы, представляющей конкретную сущность в мире данной програм-
программы. Приведенные правило и факт содержат явные знания, относящиеся
только к человеку по имени Джон.
*) Хэкер - компьютерный хулиган. - Примеч. пер.
64 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Употребление переменной вместо константы
Переменная в языке Пролог записывается как слово, шчинающееся
с большой буквы. Правило "получать_по_шее", приведенное ранее, можно
обобщить на всех хэкеров, если константу «джон » заменять на пере-
переменную:
получать_по_шее (X) :— хэкер (X).
Это можно прочесть так:
Если X - хэкер, то он/она получает по шее.
Или же так:
Все хэкеры получают по шее.
Переменная X согласуется с любой константой, поэтому данное правило
можно применить для доказательства того, что любой хэкер получает по
шее. Это правило содержит переменные, и поэтому оно выражает неявные
знания, относящиеся ко всем хэкерам.
Декларативный стиль
Заметьте, что приведенные правила являются просто объявлениями
отношений между сущностями. Пролог-программы почти исключительно
состоят из таких объявлений, в этих программах не употребляются обще-
общепринятые управляющие структуры (do, while, for, goto и т.д.), специфи-
специфицирующие порядок выполнения программы. Программист может перело-
переложить на механизм решения задач многие решения, касающиеся хода выпол-
выполнения программы. Некоторые из языков запросов к базам данных (к при-
примеру, язык SQL) также декларативны. Пользователь лишь должен ука-
указать то, какой тип ответа требуется, а интерпретатор языка запросов са-
самостоятельно принимает решение о том, как получить ответ.
0.9. ФРАЗЫ ХОРНА КАК СРЕДСТВО ПРЕДСТАВЛЕНИЯ ЗНАНИЙ
Решение задач
Конечной целью составления компьютерной программы является созда-
создание инструмента, предназначенного для решения задачи из некоторой при-
прикладной области. Прикладная область - это некоторая абстрактная часть
мира, или область знаний. Структура прикладной области состоит из зна-
значимых для этой области сущностей, функций и отношений. В удачной
компьютерной программе структура прикладной области моделируется
таким образом, что поведение этой программы во время выполнения бу-
будет отражать какие-то существенные аспекты данной структуры. К приме-
примеру, отношение, существующее между некоторыми сущностями прикладной
области, должно, по аналогии, соблюдаться и для обозначений, которые
представляют эти сущности в программе, моделирующей эту область.
0.9. ФРАЗЫ ХОРНА КАК СРЕДСТВО ПРЕДСТАВЛЕНИЯ ЗНАНИЙ 65
Программирование
Процесс составления компьютерной программы, моделирующей струк-
структуру прикладной области, обычно состоит иа двух этапов:
1) необходимо проанализировать структуру прикладной области и
представить эту структуру в виде логической спецификации данной об-
области;
2) следует написать программу, реализующую структуру, которая
описана в логической спецификации.
Если языком программирования служит Пролог, то процесс написания
программы, моделирующей структуру прикладной области, в основном
сходен с процессом построения теории в логике предикатов (см. разд. 0.5).
В целом написание программы состоит из следующих шагов:
1) Программист анализирует значимые сущности, функции и отноше-
отношения из прикладной области и выбирает обозначения для них. (В приве-
приведенном выше примере программист обозначил константу идентификато-
идентификатором <<джон», а предикаты — идентификаторами <<нолучать_по_шее»
и « хэкер ».)
2) Программист семантически определяет каждую значимую функ-
функцию и каждое значимое отношение. Для отношений указывается, какие
конкретные их реализации дают истину, а какие — ложь.
3) Программист аксиоматически определяет каждое отношение при
помощи фраз Пролога. (В приведенном выше примере единственная фраза
<< иолучать_по_шее(Х) :— хэкер (X)» — это аксиоматическое определение
отношения "получать_по_шее".) Аксиоматическое определение отношения
будет удачным, если оно отразит смысл семантического определения. Мно-
Множеством аксиоматических определений всех значимых для заданной пред-
предметной области отношений является программа, моделирующая структуру
этой области.
4) Для выполнения запросов к множеству фраз программы програм-
программист или пользователь применяет интерпретатор языка Пролог. Совокуп-
Совокупность, состоящую из запроса, множества фраз программы и интерпрета-
интерпретатора языка можно рассматривать как алгоритм решения задач из приклад-
прикладной области. При этом запрос и фразы программы представляют собой
начальные формулы алгоритма, а интерпретатор содержит правила преоб-
преобразования этих формул. Интерпретатор играет роль активной силы, кото-
которая выполняет выводы из фраз программы и тем самым реализует или
развертывает отношения, определенные фразами программы. Ответ ин-
интерпретатора на запрос отражает структуру прикладной области. Этим
ответом можно воспользоваться при решении задач из прикладной об-
области.
Ковальски кратко описывает этот вид алгоритмов решения задач
следующим "уравнением" [56]:
Алгоритм = Логика + Управление
3. Дж. Малпас
66 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
"Логика" здесь обозначает ту часть программы, которая моделирует
структуру области. Если языком программирования служит Пролог, то
"Логика" обозначает аксиоматическое определение важных отношений
из прикладной области. "Управление" обозначает процедуру (или про-
процедуры), способную выполнять выводы из "логической" части програм-
программы, другими словами, реализовать ее смысл. При пользовании языком
программирования Пролог значительная часть "Управления" выполня-
выполняется интерпретатором.
Способность представлять знания о прикладной области — это одна
из важнейших отличительных особенностей многих типов программ ис-
искусственного интеллекта. Знания о прикладной области равнозначны
проведению анализа значимых сущностей, функций и отношений из этой
области. Поэтому при составлении адекватной Пролог-программы необ-
необходимо реализовать представление знаний о данной области, а фразы Про-
Пролога можно рассматривать как язык представления знаний. Тема пред-
представления знаний более глубоко освещается в гл. 6.
0.10. СЕМАНТИКА ПРОЛОГА
Три семантические модели
Термин семантика (смысл) формулы символической догики отно-
относится к истинностному значению этой формулы. Когда говорят о семан-
семантике константы в формуле, то имеют в виду ее истинностное значение
с учетом области интерпретации. С другой стороны, когда речь заходит
о вычислениях, то под семантикой некоторой конструкции языка про-
программирования обычно понимается поведение компьютера при выпол-
выполнении этой конструкции. Поскольку Пролог одновременно является и
логическим языком, и языком программирования, то к нему применимы
все эти трактовки термина семантика.
Для объяснения смысла Пролог-программы применяются три семан-
семантические модели: декларативная модель, процедурная модель и модель
в виде абстрактной машины. Существование трех семантических моделей
придает языку Пролог большую выразительность.
Декларативная модель
В декларативной семантической модели Пролога специфицируются
истинностные значения конкретных случаев отношений. Здесь употребля-
употребляется слово декларативный, потому что во фразах языка Пролог декла-
декларируется (т.е. объявляется), что будут соблюдаться некоторые отношения
между аргументами, если выполнены все условия, входящие в эти фразы.
К примеру, фразу
начальник (Фамилия, Оклад) :— ¦?
служащий (Фамилия, Оклад), Оклад > 70000.
,-J
f
10. СЕМАНТИКА ПРОЛОГА . 67
можно прочесть так:
Некое лицо (Фамилия) является начальником, если
он или она является служащим
с окладом, превышающим 70000 долларов.
В соответствии с прочтением дня декларативной модели фразы Про-
лсна являются формулами логики предикатов первого порядка, записан-
записанными в форме фраз Хорна. В качестве логических соединителей могут
выступать только лишь "если", "и" и "или". Порядок следования условий
не имеет значения, так как считается, что все условия должны соблюдаться
одновременно. Множество фраз, составляющих Пролог-программу, описы-
описывает существенные особенности логической структуры прикладной области.
Процедурная модель
В соответствии с процедурной семантической моделью Пролога усло-
условия, входящие в состав фразы, специфицируют процесс установления
истинностного значения данной фразы. Тем самым условия трактуются
как последовательность шагов, которые необходимо успешно выпол-
выполнить для того, чтобы соблюдалось отношение, приведенное в заключе-
заключении этой фразы. Множество фраз с одним и тем же именем предиката и
с одинаковым количеством аргументов трактуется как процедура. За-
Запрос с указанием того же имени предиката и того же числа аргументов,
что и в процедуре, трактуется как вызов этой процедуры. Для того что-
чтобы запрос оказался успешным, необходимо, чтобы вызываемая в нем про-
процедура была успешно выполнена. Каждое условие во фразе также пони-
понимается как вызов процедуры.
При процедурном прочтении смысл приведенной выше фразы "на-
"начальник" будет таким:
Один из способов обнаружить начальника - это:
во-первых, отыскать служащего
и, во-вторых, проверить, превышает ли оклад
этого служащего сумму в 70000 долларов.
Для процедурной модели важен порядок, в котором выполняются условия.
Модель в виде абстрактной машины
При прочтении с позиций декларативной модели Пролог-программа —
это описание логической структуры. Интерпретатор языка Пролог служит
активной силой (т.е. процедурой), которая способна вывести следствия
из эТого описания. При выполнении запроса интерпретатор применяет по
отношению к множеству фраз Пролога некоторую стратегию решения
задачи. С точки зрения 'вычислений эта стратегия может быть описана
при помощи некоторой абстрактной машины. В языке Пролог запрос
3*
68 ГЛ. 0. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
и множество фраз программы имеют вычислительный смысл. Это прояв-
проявляется в том, что они вызывают определенное поведение интерпретатора
Пролога. Модель в виде абстрактной машины описывает смысл запроса
и множества фраз через действия этой машины.
Как отмечалось в разд. 0.6, действия такой абстрактной машины мож-
можно рассматривать как применение правила резолюции. Можно также пояс-
пояснить действия этой машины и через операции со стеком. Такое объяснение
предлагается в гл. 3.
Сферы употребления моделей
У каждой из трех описанных моделей есть свои сильные и слабые сторо-
стороны. Декларативная модель наиболее близка к семантике логики преди-
предикатов, что делает Пролог эффективным языком для представления знаний.
Однако в декларативной модели нельзя адекватно представить ie
фразы, в которых важен порядок следования подцелей. Ярким примером
такой ситуации может служить фраза, которая вызывает выходные по-
побочные эффекты, скажем, вывод в определенном порядке сообщений
на экран дисплея. Для пояснения смысла фраз такого рода необходимо
воспользоваться процедурной моделью.
Но даже процедурная модель не годится для разъяснения смысла
фраз, вызывающих побочные эффекты управления, такие как остановка
выполнения запроса или удаление фразы из программы. Смысл таких фраз
можно объяснить только с помощью модели в виде абстрактной машины.
Модель в виде абстрактной машины является наиболее точной из трех
описанных моделей, но она является и наиболее зависимой от реализации
языка.
Процедурная и декларативная модели рассматриваются в гл. 1. Мо-
Модель в виде абстрактной машины обсуждается в гл. 3. В гл. 4 рассказы-
рассказывается о том, как эти три семантические модели могут влиять на практику
программирования.
0.11. МЕТАЯЗЫК / ОБЪЕКТНЫЙ ЯЗЫК
Функции метаязыка
При изучении логики обычно используется некоторый формальный
язык. Ранее в данной главе были рассмотрены два таких языка — логика
высказываний и логика предикатов. В предыдущем разделе отмечалось,
что Пролог тоже является формальным языком, если подходить к нему
с позиций декларативной семантической модели. Для того чтобы обсуждать
свойства формального языка, необходимо воспользоваться языком, от-
отличным от этого формального языка. Принято называть формальный
язык объектным языком, а язык, применяемый при рассмотрении фор-
формального языка, — метаязыком (см. разд. 0.4).
I. МЕТАЯЗЫК / ОБЪЕКТНЫЙ ЯЗЫК 69
Метаязык выполняет две функции — аналитическую и предписываю-
ую. Аналитическая функция метаязыка заключается в том, чтобы дать
[рактеристику предложениям объектного языка с помощью таких
ойств, как тавтология или противоречие. Она позволяет также охаракте-
1зовать теории объектного языка и сам объектный язык при помощи
ких свойств, как полнота и последовательность. Три закона логики
;м- табл. 0.1) — это предложения метаязыка, описывающие природу
5ъектного языка.
Предписывающая функция метаязыка состоит в том, чтобы уста-
уставить истинностные значения предложений объектного языка, не являю-
ихся ни тавтологией, ни противоречием. (Если предложение объектного
1ыка не является ни тавтологией, ни противоречием, то его значение
:тинности Нельзя установить на основе правил одного лишь объектного
1ыка.) Метаязык дает возможность судить об истинностном значении
эедложения объектного языка на основании сведений, содержащихся
источниках знаний, которые не принадлежат к объектному языку, т.е. на
:новании интуиции, здравого смысла или знаний о прикладной области,
этом смысле метаязык позволяет вводить аксиомы теории, описываю-
ие структуру некоторой прикладной области. Сходным образом добав-
:ние новой фразы в Пролог-программу является функцией метаязыка.
Синтаксическая связь между объектным языком и метаязыком
В логике предикатов атомарная формула — это самая простая конст-
кция, обладающая истинностным значением. Атомарная формула со-
оит из обозначения предиката и некоторого количества термов, среди
'торых ни один не может самостоятельно обладать значением истин-
1сти. Если предложение метаязыка описывает свойство предложения
ъектного языка, то между этими двумя предложениями будет существо-
1ь важная синтаксическая связь: предложение объектного языка служит
шом предложения метаязыка, т.е. синтаксическим объектом, кото-
№ не может обладать истинностным значением. Рассмотрим следующее
едложение метаязыка:
Р(а, Ь) доказуемо.
этом примере "доказуемо" является предикатом метаязыка, а предло-
предложив объектного языка Р(а, Ь) служит аргументом данного предиката,
м по себе терм Р(а, Ь) не обладает значением истинности. Истинностное
вчение этого терма определяется тем предложением метаязыка, в состав
оторого он входит. Метаязык обязательно содержит предикаты (к приме-
примеру "доказуемо"), не являющиеся частью объектного языка. . ~.
70 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Метаязык Пролога
Неявный вопрос, содержащийся в запросе
Взаимодействие между пользователем и интерпретатором Пролога
можно рассматривать как на уровне объектного языка, так и на уровне
метаязыка. Если подходить с позиций объектного языка, то пользователь
при вводе запроса к интерпретатору неявно задает и такой вопрос:
Соблюдается ли отношение, описанное в данном запросе ?
Но на уровне метаязыка неявный вопрос будет следующим:
Является ли отношение, описанное в данном запросе, доказуемым
при помощи стратегии решения задач интерпретатора в соответствии
с множеством фраз, содержащихся в текущей программе!
Запрос сам по себе — это предложение объектного языка, а характеристи-
характеристика "быть доказуемым при помощи стратегии ... в соответствии с мно-
множеством фраз, содержащихся в текущей программе" может быть свойст-
свойством этого предложения. Интерпретатор откликается на запрос, выясняя,
какой ответ должен быть дан на него — положительный или отрицательный.
У этого ответа имеются две интерпретации. На уровне объектного языка
этот ответ говорит о том, соблюдается ли описанное в запросе отношение.
На уровне метаязыка ответ свидетельствует о том, доказуемо ли или нет
данное отношение при помощи стратегии решения задач интерпретатора
в соответствии с множеством фраз, входящих в текущую программу.
Как осуществляется ответ на вопрос
4 Интерпретатор обрабатывает запрос следующим образом. Если фраза
программы, согласующаяся с запросом, не имеет условий, то запрос будет
успешным (т.е. на него будет дан положительный ответ). Если в програм-
программе отсутствуют фразы, согласующиеся с запросом, то он потерпит неудачу
(т.е. будет дан отрицательный ответ на запрос). Если же фраза, согласую-
согласующаяся с запросом, снабжена некоторыми условиями, то запрос будет
успешным только в том случае, когда интерпретатор сможет установить,
что все условия истинны. В противном случае запрос окажется неудачным.
Если в запросе содержится переменная, то интерпретатор попытается найти
такие ее значения, при которых отношение, описанное в запросе, будет
соблюдаться.
Предположение о замкнутости мира
Если запрос терпит .неудачу, то это означает, что интерпретатор не смог
выполнить его доказательство по множеству фраз, которые содержатся
в текущей программе. Таким образом, интерпретатор языка Пролог исхо-
исходит из предположения о том, что если соблюдение некоторого конкретного
случая отношения доказать нельзя, то этот случай отношения является
О. I I. МЕТАЯЗЫК / ОБЪЕКТНЫЙ ЯЗЫК 71
ложным. Здесь не делается различия между неизвестным отношением и
01 ношением, неистинность которого доказуема. Множество фраз текущей
Программы иногда называют миром. Тот фа^кт, что Пролог действует так,
как будто бы множество фраз текущей программы является единственным
источником знаний, известен как предположение о замкнутости мира.
Пусть в текущей программе имеется только лишь одна фраза, в кото-
которой утверждается, что:
Человек является выходцем из Франции, если его фамилия -Делакруа.
Если мы напишем запрос о том, является ли мистер Шевалье выходцем
из Франции, то будет получен отрицательный ответ. На ypoBjie же мета-
метаязыка это будет означать, что утверждение о том, является или нет мистер
Шовалье выходцем из Франции, недоказуемо. Если принять во внимание
предположение о замкнутости мира, то фактический смысл приведенной
выше фразы будет таким:
Человек является выходцем из Франции тогда и только тогда, когда
его фамилия - Делакруа.
Здесь член "только тогда" относится к метаязыку. Обсуждение предполо-
предположения о замкнутости мира будет продолжено в разд. 3.2.
Предикаты метаязыка
На языке Пролог можно написать такую программу, которая будет
действовать как предикат метаязыка. Эта программа может потребовать-
потребоваться для того, чтобы изменить неявный метаязыковый смысл запроса. Необ-
Необходимость в этом может возникнуть либо когда нужно применить стра-
стратегию решения задач, отличающуюся от стратегии интерпретатора языка
Пролог, либо когда требуется использовать источник знаний, отличный
от множества фраз текущей программы.
Классическим примером предиката метаязыка служит предикат "демо"
(сокращение от "продемонстрировать") ([6, 55, 73]). В одной из версий
предиката "демо" приобретают явную форму и стратегия, и источник зна-
знаний. У этого предиката имеется три аргумента: запрос, который необходи-
необходимо выполнить, название стратегии решения задач и название мира (т.е. мно-
множества фраз). Заключение для предиката "демо" выглядит так:
[ демо (Запрос, Стратегия, Мир) : —
Если вызов "демо" принесет положительный результат, то это будет озна-
означать, что:
Запрос (аргумент 1) доказуем
при помощи стратегии решения задач (аргумент 2)
в соответствии с множеством фраз, образующих мир (аргумент 3) ¦
72 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
В разд. 7.5 будет описан интерпретатор, реализованный на языке Про-
Пролог, в котором применяется стратегия решения задач, отличающаяся от
собственной стратегии стандартного интерпретатора языка Пролог. Этот
новый интерпретатор можно рассматривать как предикат метаязыка, так
как метаизыковый смысл oiBeia на запрос, полученного при помощи
описываемого интерпретатора, будет несколько отличаться от метаязыково-
го смысла ответа на тот же самый запрос, полученного обычным интерпрета-
интерпретатором языка Пролог. Гот факт, что можно написать интерпретатор языка
Пролог на самом Прологе, демонстрирует расширяемость этого языка
программирования.
0.1?. СФЕРЫ ПРИМЕНЕНИЯ ЯЗЫК4 ПРОЛОГ
Язык Пролог использовался при созданы* ряда программ как дла
области искусственного интеллекта, так и для традиционных областей при-
применения. Некоторые сферы применения Пролога перечисляются ниже.
Реляционные базы данных
Поскольку модель реляционной базы данных представляет собой
хорошо разработанный логический формализм, представление ее на Проло-
Прологе реализуется достаточно прямолинейно. Пролог оказался особенно полез-
полезным при создании интерфейсов реляционных баз данных с пользователем.
На Прологе были реализованы все типы языков запросов, включая QBE,
SQL, реляционную алгебру [61] и язык, похожий на Visicalc [59]. Описа-
Описание различных интерфейсов баз данных будет представлено в гл. 3, 5 и 6.
Программная инженерия
Исследователи, специализирующиеся на программной инженерии,
показали, что логическую спецификацию системы можно непосредственно
преобразовать в логическую программу ([31,58]).
Естественный язык
Кольмерор, создавший язык Пролог, первоначально предназначал его
для обработки естественного языка. Он разработал на Прологе систему
грамматического разбора естественного языка нисходящим методом.
Использованный им формализм впоследствии получил название граммати-
грамматики определенных предложений (Definite Clause Grammar, сокращенно -
DCG) [24]. Дал, Уоррен, Перейра и другие ученые доработали DCG-фор-
мализм и продемонстрировали его успешное применение на примере сис-
систем, которые обрабатывают запросы, сформулированные на естественном
языке ([28, 84, 85]). Система СНАТ-80, созданная Перейрой, служит при-
примером системы обработки естественного языка, основанной на исполь-
использовании DCG-формализма [110].
Г;ИПЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ 73
В ряде работ по вычислительной лингвистике основным методом обмена
информацией считается унификация (унификация — это механизм, посред-
посредством которого получают значения переменнйе в языке Пролог). Так назы-
называемые формализмы грамматик унификации включают GPSG [34], HPSG
[ИЛ-FG ([49, 113] ),PATR-1I [99] и FUG [51]. а также и DCG.
В настоящее время на Прологе реализуются несколько серьезных ис-
исследовательских проектов по естественному языку, в их числе проект
l-'pistlc фирмы IBM [69] и различные проекты института ICOT ([65,
10'/. 1081).
Обсуждение проблем обработки естественного языка выходит за
амки цанной книги, но в гл. 5 рассматриваются основные методы грамма-
ческого разбора нисходящий и восходящий разбор.
Представление знаний
Все основные концепции, используемые в формализмах представле-
гя знаний для задач искусственного интеллекта, включая
семантические сети,
фреймы,
правила продукций и
объектно-ориентированное программирование,
Ьжно выразить при помощи логики и реализовать средствами логическо-
программирования. Эта тема детально освещается в гл. 6.
Экспертные системы
При представлении знаний одной из главных задач является выбор
«сой формы представления, которая может быть использована в эксперт-
>ix системах. При помощи Пролога'были построены экспертные систе-
ы для ряда сфер, включая решение уравнений [13], медицину ([29, 38]),
конодательство ([94, 27]), юриспруденцию, архитектуру [103], автома-
[Зацию заводского производства, проектирование электронных схем
[109, ) J5]), синтез микропрограмм ([86]), анализ финансового положе-
1я и помощь в принятии решений ([5е). 60]). Вопросы построения
Перфейса экспертной ci-сгемы с пользователем обсуждаются в гл. 7.
БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ
В число вводных учебных курсов по логике высказываний и логике
чг:цикатов входят работы [26, 37, 71]. В работах [15] и [64] те же темы
>ещаются с вычислительных позиций. Философская точка зрения на
мдиционную логику лучще всего излагается в работах [47] и [104].
...гория развития формальной логики отражена в работах [8, 30, 43, 75,
17] и, в особенности, в работе [92] - в приложении "Исторические за-
затки".
74 ГЛ. О. ЛОГИКА, ЛОГИЧЕСКОЕ ПРОГРАММИРОВАНИЕ И ПРОЛОГ
Наиболее полное освещение правила резолюции дано в работе [92]
Эта тема также затрагивается в [12, 15, 55]. История развития логическо-
логического программирования рассмотрена в [100, 101]. Теория логического прог-
программирования лучше всего излагается в работах [55, 46, 62].
Язык Пролог рассматривается в работах [22, 20, 46, 53]. Для обуче-
обучения практическому программированию на Прологе лучше всего подходит
книга Кларка и Маккейба, хотя синтаксис всех приведенных там примеров
соответствует синтаксису микро-Пролога. Реализация Пролога освещается
в работах [14, 46, 53]. Взгляды па Пролог специалистов-ортодоксалов,
работающих в области искусственного интеллекта, изложены в работе [4].
Различие между метаязыком и объектным языком впервые было от-
отмечено Гильбертом [44], оно послужило средством, помогающим избе
жать возникновения логических парадоксов. Роль метаязыка в формаль-
формальной логике исследуется в работах [75], [88, с. 9—17] и [71, с. 32]. Роль
метаязыка в логическом программировании обсуждается в [6, 7, 55].
Интересный способ применения предикатов метаязыка предложен
в работах [52, 73].
Семантика языков логического программирования обсуждается в ра-
работе [ 116], а также во всех перечисленных книгах по логическому програм-
программированию. Важность семантики для представления знаний подчеркивает-
подчеркивается в работах [12,9, 41].
ГЛАВА 1
ФАКТЫ И ПРАВИЛА
1.1. ИСПОЛЬЗОВАНИЕ ЯЗЫКА ПРОЛОГ
Вызов транслятора языка Пролог
Автор выражает надежду, чго читатели изучают данную книгу, имея
"под рукой" компьютер с некоторой версией языка Пролог. Если дело
обстоит именно так, то первым делом нужно научиться вызывать интер-
ретатор Пролога. Полезно несколько раз войти в интерпретатор Пролога
выйти из него, чтобы хорошо освоить эту процедуру. К сожалению,
пособ вызова транслятора языка Пролог будет различным для разных
ерсий языка и при различном операционном окружении. Рекомендуется
братиться к руководству по языку Пролог для Вашей ЭВМ и выяснить,
ак выполняются перечисленные ниже основные операции. '
г Основые операции
| 1) вызов транслятора Пролога при помощи средств операционной систе-
системы;
2) выход из транслятора Пролога;
3) применение текстового редактора для создания файла с Пролог-про-
Пролог-программой ;
4) загрузка файла с Пролог-программой во время сеанса работы с ин-
интерпретатором язы ка Пролог;
5) ввод программы в диалоговом режиме во время сеанса работы с ин-
интерпретатором языка Пролог.
После того как Вы освоите эти основные операции, двигайтесь даль-
:е и приступайте к изучению конкретных возможностей Вашей зерсии
зыка. Выясните следующее:
Особые средства некоторых версий Пролога
* какая команда позволяет переписать текущую программу в файл во
время работы с интерпретатором Пролога!
f * какие средства редактирования программы доступны во время сеанса
I работы с интерпретатором языка Пролог ?
j * какая команда применяется для компиляции (а не интерпретации)
;. Пролог-программы, находящейся 'в файле ?
76 ГЛ. 1. ФАКТЫ И ПРАВИЛА
Синтаксис различных версий Пролога
В оставшейся части книги все примеры программ написаны с исполь-
использованием синтаксиса "ядра Пролога". Сообщение-подсказка (или "пригла-
"приглашение") верхнего уровня выглядит так:
Когда на терминал выводится приглашение верхнего уровня, то это озна-
означает, что интерпретатор Пролога находится в командном режиме и ожидает
ввода запроса.
"Ядро Пролога" — это подмножество первоначальной версии языка для
ЭВМ DEC-10. Оно стало фактическгм стандартом языка по той простой при-
причине, что оно совместимо с очень большим числом версий Пролога. В то же
время авторы различных реализаций Пролога^Пбсчитали нужным изменить
некоторые детали языка и несколько расширить его. В приложении IV
рассказывается о конкретных особенностях ряда версий языка Пролог.
Если какой-либо пример из данной книги не будет работать в Вашей вер-
версии языка, то, обратившись к приложению IV, Вы сможете выяснить,
какие изменения нужно внести в текст программы из этого примера, что-
чтобы обеспечить ее работоспособность.
Интерпретатор Пролога
В настоящей книге термин интерпретатор Пролога используется не-
несколько нестрого для обозначения механизма решения задач при помощи
языка Пролог. Более точными терминами были бы система выполнения
Пролог-программ или исполнитель Пролог-программ. Интерпретатор
языка Пролог — это та "активная сила", которая фактически выполняет
программы, написанные на Прологе.
1.2. ФАКТЫ
Части Пролог-программы
Программа на Прологе состоит из множества фраз, и ее можно рассмат-
рассматривать как сеть отношений, существующих между термами. Каждый терм
обозначает некоторую сущность, принадлежащую миру. Фраза — это либо
факт, либо правило. Факт — это утверждение о том, что соблюдается неко-
некоторое конкретное отношение. Он записывается как имя, за которым сле-
следует список термов (они называются аргументами) ^заключенный в скоб-
скобки. Правило — это факт, истинностное значение которого зависит от зна-
значений истинности других фактоэ.
Сравнение предиката и процедуры
Иногда термины процедура и предикат используются почти как сино-
синонимы, хотя между ними есть различие. И предикат, и процедура иденти-
1.2. ФАКТЫ 77
фицируются именем предиката и количеством аргументов *). Предикат —
•ло абстрактный смысл существующего отношения между некоторым ко-
количеством аргументов. Процедура — это множество фраз, заголовки кото-
которых содержат одинаковые имена предикатов и одно и то же количество
аргументов. В языке Пролог предикат определяется (реализуется) при по-
помощи процедуры.
Форма записи фактов в Прологе
Факт — это фраза без условий. Факт используется для того, чтобы
показать простую взаимосвязь данных. Нижеследующий факт выражает
ммсль о том, что Мэри знает Боба:
знает(мэри, боб).
Сточки зрения синтаксиса факт состоит из имени предиката («знает»)
и списка аргументов, заключенного в скобки («мэри, боб»). Програм-
Программист сам решает, как следует читать факт, записанный на Прологе, чтобы
это звучало осмысленно на естественном языке. Обычно выбирается такое
имя предиката, чтобы оно отражало определенный вид взаимосвязи меж-
между аргументами. Аргументами факта должны быть термы. Одним из видов
•термов являются атомы. Атом — это константа, которая обычно записы-
записывается в виде некоторого слова, начинающегося с маленькой буквы. В при-
приведенном выше факте термы "мзри" и "боб" являются атомами.
Количество аргументов
Предикат может обладать произвольным количеством аргументов.
Нижеследующий факт показывает, что отель Милфорд Плаза находится
ilia пересечении 8-й авеню и 43-й стрит:
| % место авеню стрит
I расположение (отель_милфорд_плаза, 8, 43).
Символ % означает, что часть строки, следующая за ним, является ком-
комментарием. (Сам символ % также входит в состав комментария.) Если
у факта много аргументов, то в программу рекомендуется ввести ком-
комментарий, поясняющий этот факт.
i Следующий факт показывает, что одним из возможных видов транс-
Inopra для того, чтобы добраться в 2 часа дня от Всемирного торгового
^центра до отеля Милфорд Плаза, служит такси:
Г % из в вид время
транспорт (втц, милфорд_плаза, такси, 1400).
*)Для обозначения количества аргументов преднката языка Пролог употребляет-
употребляется слово "arity", которое можно перевести как "аргументность". - Примеч. пер.
78 ГЛ. 1. ФАКТЫ И ПРАВИЛА
База данных, состоящая из фактов
Простейшая Пролог-программа — это множество фактов, которое!
неформально называют базой данных. Пример базы данных, состоящей
из фактов "знает": у \
знает(мэри, боб).
знает(сэм, боб).
знает (сэм, патриция).
Совокупность этих фактов, взятых вместе, определяет предикат "знает/2",
где "знает" — имя предиката, а " — количество аргументов (arity) пре-
предиката.
Ввод программы
Пролог-программу, такую, скажем, как приведенная выше база дан-
данных "знает", можно ввести в ЭВМ одним из двух следующих способов:
1) при помощи текстового редактора создается файл с программой, кото-
которая затем загружается интерпретатором Пролога; 2) программа вводится
непосредственно с терминала во время сеанса работы с интерпретатором
Пролога. При работе с версиями Пролога, сходными с версией языка для
ЭВМ DEC-10, непосредственный ввод программы будет происходить так:
! ?- consult (user).
< введите текст программы > '
< для возврата в командный режим введите
признак конца файла >
: ?- ..;
Ввод команды consu)t(user), что в переводе на русский язык означает "про-
"просмотр (пользователь)", переключает интерпретатор в режим ввода прог-
программы *). Ввод признака конца файла возвращает интерпретатор обратно
в командный режим, о чем свидетельствует появление сообщения-под-
1.3. ЗАПРОСЫ К БАЗЕ ДАННЫХ
Составление запроса
После того как интерпретатор выполнит просмотр базы данных, можно
написать запрос к ней. Простой запрос состоит из имени предиката, за ко-
которым располагается список аргументов. (Синонимом слова запрос являет-
является слово цель). Приглашение | ?— означает, что интерпретатор готов к об-
обработке запроса.
*) В данной книге словом "просмотр" называются действия, предпринимаемые
интерпретатором при вводе Пролог-текста из файла или с терминала. — Примеч. пер.
1.3. ЗАПРОСЫ К БАЗЕ ДАННЫХ 79
Если база данных "знает" просмотрена интерпретатором, то можно
¦ шисать, к примеру, такой запрос к ней:
! ?— знает (мэри, боб).
Wo означает вопрос: "Знает ли Мэри Боба'?". Интерпретатор найдет соот-
нотствующий факт в базе данных и.ответит:
да
Примечание: в книге принято, что ответы интерпретатора печатаются
урсивом. Данный ответ можно трактовать так: Да, Мэри знает Боба".
Запросы с константами
Если в запрос не входят переменные, то интерпретатор выдает один
ю двух ответов:
да
или
нет
Ответ (^^свидетельствует о том, что интерпретатор смог доказать истин-
истинность запроса в соответствии с множеством фраз, загруженным в данный
момент времени. Ответ нет означает, что интерпретатор оказался не в со-
состоянии доказать истинность запроса.
Запросы с переменными
Переменная - это вид терма, который записывается как слово, начи-
начинающееся с большой буквы, к примеру, X или «Кто». Если в запрос
входят переменные, то интерпретатор попытается отыскать такие их зна-
значения, при которых запрос будет истинным. Запрос
; ? - знает (мэри, Кто).
означает: "Кого знает Мэри?"
Квантификация переменной в запросе
Считается, что переменные в Прологе квантифицированы экзистенци-
экзистенциально. Это означает, что в запросе., содержащем переменную неявно, спра-
спрашивается о том, существует ли хотя бы одно значение этой переменной,
при котором запрос будет истинным. Если иметь зто в виду, то приведен-
приведенный выше запрос можно прочесть так:
Существует ли хотя бы один человек, которого знает Мэри?
Эют запрос будет истинным, если такое лицо будет найдено в текущей
базе данных "знает".
*)Ответы интерпретатора — да (yes) и нет (по) — даются в русском переводе. —
Примеч. ред.
80 ГЛ. 1. ФАКТЫ И ПРАВИЛА
Выполнение запроса
Интерпретатор пытается унифицировать (т.е. согласовать) аргументы
запроса с аргументами фактов, входящих в базу данных "знает". В рас-
рассматриваемом случае запрос окажется успешным при сопоставлении запро-
запроса с первым же фактом, поскольку атом "мэри" в запросе унифицируется!
с атомом "мэрн"' в этом факте, а переменная "Кто" унифицируется с ато-
атомом "боб'', входящим в факт. В результате данного процесса переменная
« Кто )) примет значение атома ((боб », и интерпретатор ответит:
Кто = боб
Конкретизация
Говорят, что переменная конкретизируется, когда при выполнении
запроса она унифицируется с некоторым значением.
Более чем один ответ
Следующий запрос предназначен для выдачи имен всех лнц, знающих
друг друга в соответствии с фактами, содержащимися в базе данных
"знает".
! ?-знает (А, Б). v'
А = мэри -
Б = боб;
Ввод символа ; после первого ответа означает отказ от отве-та. Это побуЖ"
дает интерпретатор приступить к поиску другого ответа: t
А = сзм
Б = боб ; : •
А = сэл< \
Б = патриция ; ;,'
нет
Интерпретатор нашел три ответа на запрос. Последний ответ — нет — озна-
означает, что интерпретатор достиг конца базы данных "знает" и оказался больше
не в состоянии отыскать еще какие-либо ответы.
Порядок выдачи ответов
Заметьте, что интерпретатор находит ответы в базе данных "знает"
точно в том порядке, в каком факты вводились в базу. После отыскания
первого ответа на запрос интерпретатор запоминает положение этого отве-
ответа в базе данных "знает". Если пользователь введет символ ; , то интер-
интерпретатор начнет поиск нового ответа со следующей фразы "знает". Но ес-
если пользователь нажмет клавишу возврата каретки (return), то интерпре-
интерпретатор "забудет" положение последнего ответа в базе данных "знает" и вер-
вернется к сообшению.-подсказке верхнего уровня, | ?—.
ЗАПРОСЫ К БАЗЕ ДАННЫХ 81
Продолжительность существования переменных
\ Запрос существует в интервале времени от момента, когда пользова-
пользователе наберет текст запроса и нажмет клавишу" "возврат каретки", до мо-
момента, когда на терминале снова появится сообщение-подсказка верх-
верхнего уровня. Продолжительность существования любой переменной, вхо-
входящей в запрос, будет той же, что н у самого запроса. После того как интер-
дветатор выполнит запрос и вернется к сообщению-подсказке верхнего
[шня, переменные этого запроса прекратят существование.
Составные запросы
Все приведенные выше запросы были простыми запросами. Составной
эс образуется из нескольких простых запросов, соединенных между
эй запятыми. Каждый простой запрос, входящий в составной, называет-
"подцелью". Для того чтобы составной запрос оказался истинным, не-
одимо, чтобы каждая из его подцелей была истинной. К примеру, запрос
! ?— знает (мэри. А), знает (сэм, А).
соответствует вопросу: "Есть ли такой человек, которого знают одновре-
одновременно и Мэри, и Сэм?" Одна и та же переменная А входит в обе подцели
этого запроса, а зто означает, что для истинности всего составного запро-
запроса вшрые аргументы обеих подцелей должны принимать одно и то же
значение. Интерпретатор ответит:
А = боб ;
нет
Первый ответ, А = боб, показывает, что Боба знают одновременно и Мэри,
и Сэм. Второй ответ, нет, свидетельствует о том, что Боб — это единствен-
единственный их общий знакомый.
Аргументы как входные и выходные параметры
I Выдача запроса — зто единственный способ дать команду интерпретато-
f Пролога на выполнение программы. Использование константы в качест-
аргумента запроса (скажем, констант "мэри" или "сэм" в последнем
примере) эквивалентно заданию входного параметра программы. Любой
положительный ответ должен унифицироваться' с константой. Использова-
Использование неременной в качестве аргумента запроса (скажем, переменной А в
последнем примере) эквивалентно требованию получить от программы
водные данные.
Переменная _
|Символ подчеркивания _ выступает в качестве анонимной переменной,
орая предписывает интерпретатору проигнорировать значение аргумен-
|Анонимная переменная унифицируется с чем угодно, но не обеспечи-
82 ГЛ. 1. ФАКТЫ И ПРАВИЛ/
вает выдачу на терминал выходных данных. Каждая переменная _,
щая в запрос, отличается от всех других переменных этого запроса,
Посмотрим, к примеру, что произойдет, если ввести запрос:
] ?-знает(Б,_).
При выполнении этого запроса будут выданы все возможные значения
первого аргумента предиката "знает", вне зависимости от того, какие зна
чения будет принимать второй аргумент.
Б = мэри;
Б = сэм; ¦х
Б=сэм;
нет
Как вы думаете, почему интерпретатор дважды выдал ответ Б = сэм?
1.4. ПРАВИЛА
Сравнение фактов и правил *
Факт — зто утверждение о существовании некоторого отношения меж-
между аргументами, обозначаемого именем предиката. С другой стороны, пра-
правило — это факт, значение истинности которого зависит от истинностных
значений условий, образующих тело правила.
Форма записи правила: Заголовок :— Тело
Заголовок правила имеет точно такую же форму, как и факт. После
заголовка стоит обозначение :— (которое читается как "если"), а затем
располагается тело правила. Каждое условие, входящее в тело, называется
подцелью. Для того чтобы заголовок правила оказался истииным, необхо-
необходимо, чтобы каждая подцель, входящая в тело, была истинной. Тем самым
совокупность подцелей в теле правила действует подобно составному
запросу.
ЗАГОЛОВОК если ТЕЛО
ПОДЦЕЛЬ и ПОДЦЕЛЬ
начальник (Фамилия, Окл) :^- служ (Фамилия, Окл) , Окл > 70000.
Заголовок правила сходен с макросом, который обозначает совокуп-
совокупность подцелей, входящих в его тело. Процесс доказательства истинности
запроса к некоторому правилу сходен с выполнением подстановки мак-
макроса.
f. ПРАВИЛА 83
Пример правила
Предположим, что создана база данных А'раб_смена". Каждый факт
этой базы определяет смену, в которую работает служащий. \
% служащий смена ^
раб_смена(мэри, дневная),
рабсмена (сэм, вечерняя).
раб_смена(боб, вечерняя).
раб_смена (патриция, вечерняя).
Следующее правило устанавливает, что Боб знает Мзри, если они вместе
работают в вечернюю см?;ну:
знает1 (боб, мэри) :- % заголовок
раб_смена (боб, вечерняя), % 1-я подцель тела
раб_смена (мэри, вечерняя). % 2-я подцель тела
Заголовком данного правила является «знает1 (мэри, боб)». Тело прави-
правила состоит из двух подцелей "раб_смена". Запятая, стоящая между этими
подцелями, читается как "и". Все правило можно прочесть так:
Боб знает Мэри, если
Боб работает в вечернюю смену и
Мэри работает в вечернюю смену.
Запрос к правилу
Правила опрашиваются таким же способом, как и факты. В нижесле-
нижеследующем запросе требуется выяснить, кого зиает Боб: '
| ?-знает 1 (боб, А).
А -мэри
Успешность этого запроса зависит от успешности всех подцелей, входящих
в тело опрашиваемого правила. Ответ на запрос будет отрицательным,
если интерпретатор не сможет установить, что и Боб, и Мэри работают в
вечернюю смену.
Правило, при определении которого используются переменные
Если в приведенном выше определении правила "знает" вместо кон-
констант употребить переменные, то это правило станет пригодным для того,
чтобы можно было установить, что любые два человека знают друг друга,
если они работают в одну и ту же смену:
знает2(А,Б) :—
раб_смена(А, Смена),
раб_смена(Б, Смена).
Переменная «Смена»входит в обе подцели данного правила; в каждой
84 ГЛ. 1. ФАКТЫ И ПРАВИЛА
подцели она должна иметь одно и то же значение. (Здесь предикат получил
название "зиает2", чтобы отличить его от предикатов из предыдущих
примеров, "знает" и "знаетГ'.)
Правило "знает2" является гораздо более общим, чем его предыдущая
версия ("знаетГ'), в определении которой были употреблены константы.
Правило, в состав которого входят переменные, можно рассматривать
как неявное определение множества фактов. Например, правило "знает2"
содержит те же сведения, что и нижеследующая база данных, состоящая
из фактов:
знает2(сэм, боб).
знает2 (сэм, патриция).
знает2 (боб, патриция).
Область действия переменной
Область действия некоторой переменной, входящей в правило, ограни-
ограничивается этим правилом. В Прологе отсутствуют глобальные переменные.
Например, имена переменных « А >>, «Б >> и «Смена », использованные в
правиле "знает2", можно употреблять и в других правилах данной програм-
программы, при этом между такими переменными будет отсутствовать какая-либо
связь.
Квантификация переменной, входящей в правило
Переменные, входящие в заголовок правила (скажем, А или Б в пра-
правиле "знает2"), квантифицированы универсально. Это означает, что прави-
правило, заголовок которого содержит переменные, будет истинным для любых
термов, удовлетворяющих критериям, которые заданы в теле этого прави-
правила. С другой стороны, переменные, входящие только в тело правила (к при-
примеру, переменная « Смена »), квачтифицированы экзистенциально. Если
учесть такую квалификацию, то правило "знает2" можно прочитать так:
Для любых двух лиц Аи Б
А знает Б, если
на заводе существует смена - Смена
такая, что
А работает в смену Смена и
Б работает в смену Смена.
Ниже приведены запросы к правилу "знает2". Какие результаты Вы
ожидаете получить от выполнения каждого из запросов? Будет ли для како-
какого-нибудь запроса вырабатываться более одного ответа?
?- знает 2 (боб, А).
?— знает2(патриция, мэри).
?- знает2(фрэнк,Б).
?-знает2(Б, В).
». ПРАВИЛА 85
Явные и неявные базы данных ,
База "раб_смена" - это явная база данных, так как она составлена из
актов, аргументы которых — константы; "знает2" — это неявная ба-
данных, поскольку правило "знает2" определено с использованием пере-
переленных, значения которых зависят от подцелей тела этого правила. С точ-
'¦№ <рения пользователя, составляющего запрос, не имеет значения, являет-
является ли база данных явной или неявной.
Пример: база данных "путешествие"
Приведенная ниже база данных "путешествие" содержит факты, каж-
из которых имеет по четыре аргумента. Каждый факт устанавливает,
можно совершить путешествие на транспортных средствах некоторой
С&мпании A-й аргумент) из одного города B-й аргумент — пункт от-
отправления) в другой город C-й аргумент — пункт назначения) и при этом
воспользоваться некоторым видом транспорта D-й аргумент).
% компания отправл. прибытие видтрансп.
путешествие (амтрак, нью_йорк, бостон, поезд).
i Утешествие(ндж_транзит,нью_йорк, принстои, поезд). ч"
] утешествие (амтрак, бостон, портленд, поезд).
] утешествие (грейхаунд, бостон, портленд, автобус).
: утешествие (амтрак, нью_йорк, Вашингтон, поезд).
ешествие(пиплз, нью_йорк, Вашингтон, самолет).
ешествие(пиплз, бирлингтон, ньюйорк, самолет).
Множество этих фактов определяет предикат "путешествиё/4", где
Гутешествие" — имя предиката, а " — количество его аргументов.
Определение правила "конкурент" с использованием переменных
Правило "конкурент" гласит, что любые две транспортные компании
'дут конкурентами, если они обе обслуживают один и тот же маршрут.
конкурент (Компания1, Компания2) :—
путешествие (Компания1, ГородА, ГородБ, _),
путешествие (Компания2, ГородА, ГородБ, _).
теле данного правила имеются две переменные (« Город А » и « Го
)JX Б»), входящие в состав обеих подцелей "путешествие". Четвертым ар-
ментом обеих подцелей "путешествие" служит переменная _, так как
Щ определении того, являются ли две транспортные компании конкурен-
ми, вид используемого транспорта не имеет значения. Правило "конку-
нт" можно прочесть так:
Для любых двух транспортных компаний, <<Компания1» и « Компа-
ния2»,
86
ГЛ. I. ФАКТЫ И ПРАВИЛА
«Компания1 » будет конкурентом для компании «Компания2)), если
существуют два города, «ГородА» и ((ГородБ)),
такие, что
« Компания] » обеспечивает перевозки
между городами «ГородА » и « ГородБ » и
« Компания2 » обеспечивает перевозки
между городами « ГородА » и ((ГородБ».
Запросы к правилу "конкурент"
Нижеследующие запросы дают иллюстрацию того, как можно восполь
зоваться правилом "конкурент":
! ?- конкурент(пиплз, К).
К = амтрак
! ?— конкурент (амтрак, ндж_транзит).
нет ¦
Какие результаты можно ожидать от выполнения запроса, приведенного
ниже?
! ?—конкурент(К, Л).
Косвенные отношения
Правило "можно_путешествовать", приводимое далее, устанавливав!
косвенную связь между двумя городами. Такое косвенное отношение бу-
будет соблюдаться в том случае, если возможно путешествие из одного го-
города в другой через третий — промежуточный — город.
можно_путешествовать(ГородА, ГородВ) :—
путешествие (_, ГородА, ГородБ, _),
путешествие (_, ГородБ, ГородВ, ).
В соответствии с приведенной выше базой данных "путешествие" правило
ч ' "можно путешествовать"
Портленд ) даст положительный ре-
результат для городов Нью-
Йорк и Портленд, так как
можно добраться из Нью-
Йорка в Бостон поездом
компании Амтрак, а из
Бостона - в Портленд на
автобусе компании Грей-
хаунд.
Изображение отношений
Отношение "можно__пу-
тешествовать" для случая
МОЖНО-
путешествовать
путешествие
Нью-Йорк J
Рис. 1.1
ПРОЦЕДУРЫ 87
Г'
городов Нью-Йорк и Портленд можно представить графически, если изобра-
изобразить каждый аргумент в виде точки, а каждый предикат - в виде стрелки,
соединяющей точки. Это показано на рис. 1.1. ~-
1.5. ПРОЦЕДУРЫ
Декларативная и процедурная семантика
Смысл фразы языка Пролог может быть понят либо с позиций декла-
\тивного подхода, либо с позиций процедурного подхода. До сих пор в
иной главе обсуждался только декларативный смысл фраз. Декларатив-
!Й смысл подчеркивает статическое существование отношений. Порядок
едования подцелей в правиле не влияет на декларативный смысл этого
¦вила.
Процедурная семантика
При процедурной трактовке Пролог-программы подчеркивается после-
последовательность шагов, которые выполняет интерпретатор при обработке
запроса. Таким образом, приобретает значение порядок следования под-
подцелей в правиле. Множество фраз, имеклцих одно и то же имя и одинако-
одинаковое количество аргументов, можно рассматривать как процедуру, при
этом запрос (или поцце,. лравила"! является вызовом процедуры. Когда
рпретятор обрабатывает запрос к процедуре, то он анализирует фразы,
зующие процедуру, в том порядке, как они в ней представлены.
Два смысловых значения правила "можно путешествовать"
Рассмотрим снова правило "можно_путешествовать", приведенное
. Декларативная трактовка данного правила может быть такой:
Будет возможным совершить путешествие между
городами « ГородА » и << ГородВ », если
можно добраться из города «ГородА»
в промежуточный пункт « ГородБ » ,
и
можно добраться из города « ГородБ » в « ГородВ ».
'Цедурная трактовка этого же правила будет иной:
Для того чтобы найти способ, которым
, можно добраться из города «ГородА » в «ГородВ »,
вначале
нужно найти способ передвижения из
города « ГородА » в промежуточный «ГородБ »,
затем
нужно найти способ передвижения из
города «ГородБ »в «ГородВ».
88 ГЛ. 1. ФАКТЫ И ПРАВИЛА
Версия программы "можяопутешествовать",
состоящая из двух правил
Можно предложить новую версию программы "можно_путешество-
вать", состоящую из двух правил. Фраза A) гласит, что отношение "мож-
но_путешествовать2" будет соблюдаться в том случае, если существует
фраза "путешествие", устанавливающая прямую транспортную связь меж-
между двумя нужными городами. Фраза B) совпадает с приведенным ранее
правилом "можно_путешествовать".
можно_путешествовать2 (ГородА, ГородВ) :- %A)
путешествие (_, ГородА, ГородВ, _).
можно_путешествовать2(ГородА, ГородВ) :— %B)
путешествие (_, ГородА, ГородБ, ),
путешествие(_, ГородБ, ГородВ, _).
Считается, что между этими двумя правилами неявно присутствует соеди-
соединитель "или". С декларативных позиций оба эти правила можно прочесть
так:
Путешествие из города «ГородА» в «ГородВ» будет
возможным, если либо
1) существует прямая транспортная связь между этими
городами, либо
2) можно совершить путешествие из города «ГородА»
в некоторый промежуточный пункт « ГородБ », а затем /ч
добраться из города « ГородБ >> в «ГородВ ».
Процедурная трактовка данных правил будет иной: ;1'
Для того чтобы найти способ добраться из
города « ГородА » в « ГородВ », необходимо либо , ^
1) найти прямую транспортную связь между городами,
либо
2) найти вид транспорта, связывающий «ГородА» с про межуточным
пунктом « ГородВ », а затем
найти транспортную связь между городами «ГородБ » и «ГородВ ».
Запросы к предикату "можно путешествовать!"
При обработке запроса к предикату "можно_путешествовать2" интер
претатор вначале проверяет фразу A). Если фрача A) дает отрицатель
ный ответ, то интерпретатор переходит к проверке фразы B).
i ?— можно_путешествовать2(нью_йорк, Вашингтон).
да % ответ получен по фразе A)
! ?— можно_иутешествовать2(нью_ йорк, портленд).
да % ответ получен по фразе B)
ПРОЦЕДУРЫ 89
I
Щ Как обрабатывается запрос
т Обработку последнего запроса можно представить в виде эквивалент-
эквивалентной последовательности запросов. Для наглядности запросы, соответствую-
соответствующие подцелям правил, выделены отступом.
; ?- можно_путешествовать2 (нью_йорк, портленд).
% первая подцель первого правила "можно_путешествовать2"
I ?— путешествие (__, нью_ йорк, портленд, _).
нет
% первая подцель второго правила "можно_ путешествовать2"
j ? - путешествие (__, нью__йорк, ГородБ, __).
ГородБ = бостон
% вторая подцель второго правила "можно путешествовать2"
•! ? — путешествие (_, бостон, портленд, _).
да
да
едний ответ да и будет ответом на исходный запрос к предикату
но_путешествовать2".
Соединитель "или"
В рассмотренных до сих пор телах правил подцели связывались друг
[ругом посредством соединителя "и", обозначаемого символом , (запя-
). Можно также связывать подцели (или множества подцелей) соеди-
ггелем "или", который обозначается символом ; (точка с запятой).
Некоторых версиях языка Пролог используется альтернативное обозна-
соединителя "или" — символ !.
Составные запросы, в которых употребляется символ ;
Рассмотрим запрос:
! ?- а(Х), b(X,Y); c(Z).
я того чтобы этот составной запрос оказался истинным, нужно либо
ы одновременно две подцели — а(Х) и b(X, Y) - были истинными,
чтобы подцель c(Z) была истинной. Если подцель а(X)потерпит не-
чу, то интерпретатор пропустит подцель b(X, Y) и попытается обрабо-
ь подцель с (Z).
Еще один пример употребления символа ; приводится ниже:
| ?- жена (Ж, джордж), богатый (Ж) ; богатый (джордж).
[рос будет истинным, если либо у Джорджа есть жена и она богата, ли-
если Джордж сам богат. Если подцель «жена(Ж, джордж)» потерпит
дачу, то интерпретатор не будет обрабатывать подцель «богатый (Ж) »,
сразу же перейдет к рассмотрению подцели, стоящей за символом ; ,
. к подцели « богатый (джордж) ».
90 ГЛ. 1. ФАКТЫ И ПРАВИЛА
Совместное использование соединителей , и ;
Соединитель "и", обозначаемый символом , , группирует подцепи
более тесно, чем соединитель "или", обозначаемый символом ; . В следую-
следующих примерах А, Б, В и Г обозначают произвольные подцели. В выраже-
выражениях, стоящих в правом столбце, скобки показывают подразумеваемое
группирование.
%это: означает то же самое, что и:
А; Б, В. А; (Б, В).
А, Б; В. (А, Б); В.
А, Б; В, Г. (А, Б); (В, Г).
А; Б, В; Г. А; ((Б, В); Г).
Подразумеваемое группирование подцепей, соединенных символами ; и
, всегда можно изменить при помощи скобок.
Версия предиката "можно"_путешествовать", .
в которой употребляется соединитель ;
Процедуру "можно_путешествовать2" можно переопределить и свести
к одному правилу при помощи соединителя "или":
можно_путешествоватьЗ(ГородА, ГородВ) :-
путешествие (_, Го род А, Го родВ, _)
путешествие (_, ГородА, ГородБ, _),
путешествие (_, ГородБ, ГородВ, _).
Для чего пользуются символом ; ?
Когда интерпретатор встречает приведенную выше, программную кон-
конструкцию, он преобразует ее в два правила, аналогичные процедуре "мож
нопутешествовать", текст которой был дан на одной из предыдущих
страниц. В некоторых случаях употребление символа ; улучшает читабель-
читабельность программы, так как оно позволяет обойтись одним правилом вместо
нескопьких либо устраняет необходимость написания нового предикате
для принятия единственного решения.
1.6. РЕКУРСИВНЫЕ ПРОЦЕДУРЫ
Определение понятия рекурсии
Рекурсия — алгоритмический метод, часто используемый при програм
мировании на языке Пролог. Рекурсию можно применять для достижени»
такого же эффекта, какой реализуется при употреблении итеративные
управляющих конструкций (к примеру, цикла "пока") в процедурны)
языках. В рекурсивном правиле более сложные входные аргументь
Ь6. РЕКУРСИВНЫЕ ПРОЦЕДУРЫ 9)
выражаются через менее сложные. Например, рекурсивный набор инструк-
инструкций по употреблению в пищу, растения алтей аптечный может иметь такой
вид:
Для того чтобы съесть N штук алтея аптечного, нужно:
Если N = 0, то остановиться.
Если N > О, то
проглотить одну штуку, затем
съесть N — 1 штук алтея аптечного.
Будем считать, что здесь приведено определение процедуры "съесть N
штук алтея аптечного". Символ N — аргумент процедуры. Он обозначает
некоторое целое число. Данная процедура рекурсивна, поскольку послед-
последняя строка - "съесть N - 1 штук алтея аптечного" — является вызовом
процедурой самой себя. Заметьте, что аргумент при рекурсивном вызове
N — 1 проще, чем исходный аргумент N, в том смысле, что N— 1 — это
меньшее число, чем N. Поэтому "съесть N штук алтея аптечного" представ-
представляет собой более сложный случай, выраженный через менее сложный случай
выполнения гех же самых действий, т.е. через "съесть N — 1 штук алтея
аптечного".
"Предок"
Классическим примером рекурсивного определения в Прологе может
служить программа "предок", состоящая из двух правил:
предок (А, Б) :- %A)
родитель (А, Б).
предок (А, Б) : - %B)
родитель (В, Б),
предок (А, В).
Совокупность этих правил определяет два способа, в соответствии с кото-
которыми одно лицо (А) может быть предком другого (Б). Согласно фра-
фразе A), А является предком Б, если А — родитель Б. Согласно фразе B),
А будет предком Б, если А является предком родителя Б, т.е. предком В.
Отношение, представленное в заголовке фразы B), зависит от более
простой версии самого себя — от подцели "предок".
Запросы к процедуре "предок "
Предположим, что имеется база данных "родитель":
родитель (жб, лц).
родитель (жб, гг).
родитель (гг, вм).
ff
92 ГЛ. I. ФАКТЫ И ПРАШЛ/
родитель ( гг, вм)
предок(жб, вм)
Фразв B)
предок (жб,гг) I
Фраза A)
родитель (жб, гг)
Рис. 1.2
Нижеследующие запросы иллюстрируют использование правила "предок":
% является ли жб предком гг?
| ? - нредок (жб, гг).
да % в соответствии с фразой A)
% найти всех потомков жб: - ,
! ?— предок (жб, П).
П =лц; % в соответствии с фразой A)
П -гг; % в соответствии с фразой A)
П = вм; % по фразам B) и A)
нет ;
Дерево доказательства, иллюстрирующее отношение "предок" для "жб" и
"вм", представлено на рис. 1.2.
Каждый уровень этой диаграммы демонстрирует применение одной из
фраз "предок". Первый уровень показывает, что соблюдение отношения
«предок (жб, вм) » может быть доказано только по фразе B). В этом
случае необходимо доказать одновременное соблюдение отношений
«родитель (гг, вм) » и « предок (жб, гг) ». Второй уровень показывает
что отношение «предок(жб, гг)» может быть доказано по фразе A)
В этом случае необходимо доказать только соблюдение отношения
« родитель (жб, гг) ».
Состав рекурсивной процедуры
Любая рекурсивная процедура должна включать по грайней Mept
по одной из перечисленных ниже компонент:
1) Нерекурсивную фразу, определяющую исходный вид процедуры
т.е. вид процедуры в момент прекращения рекурсии.
С РЕКУРСИВНЫЕ ПРОЦЕДУРЫ
93
2) Рекурсивное правило. Первая подцель, располагающаяся в теле
этого правила, вырабатывает новые значения аргументов. Далее размешает-
размешается рекурсивная подцель, в которой используются новые значения аргу-
аргументов.
Фраза A) процедуры "предок" определяет исходный вид этой проце-
процедуры. Как только данная фраза станет истинной, дальнейшая рекурсия
прекратится. Фраза B) — это рекурсивное правило. При каждом вызове
данное правило поднимается на одно поколение вверх. Подцель «роди-
«родитель (В, Б) )), входящая в тело этого правила, вырабатывает значение пере-
переменной В. Затем располагается рекурсивная подцель «предок (А, В) »,
в которой используется этот новый аргумент.
Неработоспособная версия процедуры "предок"
¦иже приводится версия процедуры "предок", которая не будет рабо-
работав ipn использовании большинства интерпретаторов языка Пролог.
Эта процедура, названная "нпредок", отли-
отличается от процедуры "предок" только поряд-
порядком следования подцелей в теле фразы B)
нпредок(А, Б) :- % A)
родитель (А, Б).
нпредок (А, Б) :- . % B)
нпредок (А, В),
родитель (В, Б).
С декларативных позиций смысл этой про-
процедуры идентичен смыслу процедуры "пре-
"предок". Но при процедурной трактовке смысл
процедур "предок" и "нпредок" существенно
различается. В процедуре "предок" подцель
«родитель(В, Б)» рекурсивного правила
вырабатывает новое значение переменной В,
которое затем используется в рекурсивной
подцели «предок(А, В)». С другой стороны,
¦в процедуре "нпредок" неременная В не кон-
крети шрована в момент обработки рекур-
рекурсивной подцели «нпредок(А, В)». На прак-
практике это означает, что когда интерпретатор
Рис. 1.3
будет пытаться выполнить запрос к процедуре "нпредок", то вначале он
°тыщет правильные ответы, а затем будет выполнять рекурсивные дейст-
действия вплоть до исчерпания доступного объема памяти:
i ?- нпредок (жб, П).
94 ГЛ. 1. ФАКТЫ И ПРАВИЛА
П = вм;
предупреждение: исчерпана стековая память.
Действия интерпретатора, пытающегося отыскать четвертый ответ на ддн.
ный запрос, иллюстрируются деревом доказательства, представленным
на рис. 1.3.
Процедура "нпредок" называется процедурой с левой рекурсией,
так как во фразе B) рекурсивная подцель стоит первой (т.е. он;, располо-
расположена слева от других подцелей). Интерпретатор языка Пролог не может
надежно обрабатывать леворекурсивные процедуры, что обусловлено
природой заложенной в него стратегии решения задач.
Рекурсивная версия процедуры "можно_путешествовать"
Метод рекурсии, использованный при составлении процедуры "пре-
"предок", можно с успехом применить и для написания процедуры "можно
путешествовать". В процедуре "можно путешествовать4", текст кото-
которой приведен ниже, определяется отношение между двумя городами. Это
отношение будет соблюдаться в том Случае, если можно совершить путе-
путешествие из одного города в другой через любое количество промежуточных
пунктов. Процедура "можно_путешествовать4" является рекурсивной.
Она очень похожа на процедуру "предок". Предположим, что существует
упомянутая ранее база данных "путешествие/4". Тогда отношение, опреде-
определяемое процедурой "можно путешествовать4", будет соблюдаться в тех
же случаях, что и для процедуры "можно путешествовать2", а также
и в ряде других ситуаций (скажем, для поездки между Бирлингтоном и
Портлендом через Нью-Йорк и Бостон).
можно_путешествовать4(ГородА, ГородБ) :— %A)
путешествие (_, ГородА, ГородБ, _).
можно_путешествовать4(ГородА, ГородБ) :- % B) ,}
путешествие (_, ГородА, ГородВ, J)y <\
можно_путешествовать4(ГородВ, ГородБ).
Фраза B) является рекурсивным правилом. При каждом обращении к
этому правилу должно выполняться перемещение на один город ближе к
месту назначения. Опять-таки отношение, описанное в заголовке фразы
B), зависит от более простой версии самого себя, поскольку во фра-
фразу B) входит рекурсивная подцель. Фраза A) определяет условие оконча-
окончания процесса рекурсии, т.е. исходный вид процедуры. Если фраза A)
станет истинной при выполнении запроса, то процесс рекурсии прекра-
прекратится.
г
Ы ОТНОШЕНИЙ . 95
можно_п^тешествоввтв4(бирлингтом,1юртленд)
Фраза
г^тешествие^_,5ирлингтон,нью_йорм,_) \1 1можно_путешествовать4(ныо_йорк, портлемд)
Фразв B)
|L I путешествие (_,нью_йорк,востон,_) 1/ Уможн2.п^тешествовать4Fостон,портленд)|
Фраза A)
[ путешествие^.,ныо_йорк,Портленд,,)
Рис. 1.4
Порядок выполнения запроса к процедуре
"можно_путешествовать4"
Дерево доказательства, изображенное на рис. 1.4, иллюстрирует выпол-
выполнение запроса к процедуре "можно_путешествовать4".
Эта диаграмма читается точно так же, как и предыдущее дерево дока-
доказательства.
1.7. ТИПЫ ОТНОШЕНИЙ
Характеристики отношений
Фразы Пролог-программы применяются для представления отношений
между термами. Термы обычно употребляются для представления сущ-
сущностей, входящих в мир. Поэтому для повышения эффективности програм-
программы вначале целесообразно проанализировать отношения, встречающиеся
в моделируемом мире, а затем принять решение о том, как представить
кзждый тип отношений при помощи фраз языка Пролог. Программист
может дать директиву интерпретатору языка Пролог о необходимости при-
приять во внимание свойства отношений, чтобы оптимизировать обработку
Опросов. Для простоты в оставшейся части раздела рассматриваются толь-
только отношения между двумя аргументами (т.е. бинарные отношения).
° Принципе анализ можно распространить и на отношения с большим ко-
количеством аргументов.
96 ГЛ. 1. ФАКТЫ И ПРАВИЛд
Ограничения, обеспечивающие целостность отношений. Свойства
Для аргументов любого бинарного отношения будет справедливо одц0
из следующих ограничений, обеспечивающих целостность отношения
один-к-одному
один-к-многим
многие-к-одному
многи е-к-многим
Помимо этого, некоторые отношения можно охарактеризовать наличием
или отсутствием следующих свойств:
симметрия {асимметрия)
рефлексивность (нерефлексивность)
транзитивность (нетранзитивность)
Все эти свойства и ограничения, обеспечивакнцие целостность отношение
подробно рассматриваются далее.
Ограничения вида один-к-одному
Если бинарное отношение с аргументами X и Y регулируется ограниче-
ограничением вида один-к-одному, обеспечивающим целостность этого отношения,
то это означает, что для заданного значения X существует единственное
значение Y, удовлетворяющее этому отношению, а для заданного значе-
значения Y существует только одно значение X, которое удовлетворяет, отно-
отношению. К примеру, отношение между человеком и его номером по социаль-
социальному страхованию (сокращенно — "нес") регулируется ограничением вида
один-к-одному:
нес ('Паула Смит', '347__22_5560').
(Примечание: любые символы, стоящие между апострофами, скажем,
'Паула Смит' в приведенном примере, образуют один атом.)
Применение ограничения, (
обеспечивающего целостность отношения
Ограничения, обеспечивающие целостность отношений, вступают в си-
силу либо когда в программу вводятся новые конкретные случаи отноше-
отношений (т.е. факты), либо когда в базе данных выполняется поиск конкрет-
конкретных случаев отношений.
Предположим, что имеется программа сбора данных, в которой огра-
ограничения, обеспечивающие целостность отношений, принимаются во внима-
внимание при добавлении новых фактов. Далее предположим, что отношение
"нсс/2" регулируется ограничением вида один-к-одному и что приведен-
приведенный выше факт о номере Паулы по социальному страхованию уже содеР'
J.7. ТИПЫ ОТНОШЕНИЙ 97
жигся в базе данных. Если пользователь попытается ввести в базу еше
один факт "нес" о Пауле Смит, скажем,
нес ('Паула Смит', ' 341 _22_55Ы').
jo программа сбора данных обнаружит это и откажется признать новый
факт.
, Если известно, что запрос должен иметь только один ответ, то можно
гь дирекшву интерпретатору языка Пролог о необходимости прекратить
тек дополнительных ответов после обнаружения первого ответа. В .ком
учае ограничение, обеспечивающее целостность отношения, реализуется
юграммой, которая осуществляет поиск данных в множестве фраз теку-
ей программы. При написании гвкий программы нужно воспользоваться
•едикатом "сократит!'"" [<vr), сведения о котором излагаются в гл. 3.
Ограничения вида один-к многим
Если бинарное отношение с аргументами X и Y регулируется ограниче-
ем вида один-к-многим, обеспечивающим целостность этого отношения,
это означает, что для заданного значения X может существовать много
ачепий Y, удовлетворяющих этгму отношению, но для заданного значе-
Y существует топько одно значение X, которое удовлетворяет отно-
!НИЮ.
Примером отношения, регулируемого ограничением вида один-к-мно-
м, может служить процедура "отец". У отца может быть несколько детей,
никак не наоборот.
% один много
отец(билл, даниэль).
отец(билл, кеннет).
отец(джеффри, билл).
Ограничения вида многие-к-одному
Если бинарное отношение с аргументами X и Y регулируется ограниче-
ем вида многие-к-одному, обеспечивающим целостность этого отноше-
;я, то это означает, что для заданного значения X существует только одно
ачение Y, удовлетворяющее данному отношению, но для заданного зна-
значения Y может существовать много значений X, которые удовлетворяют
отношению.
Примером отношения, регулируемого ограничением вида многие-к-од-
Ему, служит процедура "уроженец". В какой-либо стране может родиться
loro людей, но один человек может быть уроженцем только одной
раны.
% много один
уроженец (джереми, америка).
уроженец (нэн си, америка).
уроженец (рауль, франция).
4. Лж. Малпас
98 ГЛ. 1. ФАКТЫ И ПРАВИЛА
Ограничения вида многие-к-многим
Если бинарное отношение с аргументами X и Y регулируется ограниче-
ограничением вида многие-к-многим, обеспечивающим целостность этого отноше-
отношения, то для заданною значения X может существовать много значений Y,
Удовлетворяющих этому отношению, а для заданного значения Y можех
существовать много значений X, которые удовлетворяют этому отношению.
Можно привести пример базы данных, предназначенной для типограф-
типографской компании. В этой базе данных содержатся сведения о сортах бумаги.
Первый аргумент соответстьует цвету бумаги, а второй — ее виду. Разреше-
Разрешена любая комбинация цвета и вида бумаги.
% цвет вид бумаги
бумага (красный, плотная).
бумага (белый, глянцевая).
бумага (кремовый, плотная).
бумага (белый, гладкая).
Если сказать, что отношение регулируется -ограничением вида многие-к-
многим, обеспечивающим его целостность, то это эквивалентно утвержде-
утверждению о том, что отношение вообще не регулируется никакими ограничения-
ограничениями. По умолчанию интерпретатор выполняет действия с предикатами,
считая, что они регулируются ограничением вида многие-к-многим.
Симметрия
Отношение между двумя сущностями будет симметричным, если роли,
которые играют эти сущности, взаимозамеиимы. Если предикат языка
Пролог обладает свойством симметрии, то порядок следования аргументов
в запросе к этому предикату не будет иметь значения.
Примером симметричного отношения может служить отношение
"брат_или_сестра". Если известно, что Джейн - это сестра Элис, то будет
верным и тот факт, что Элис является сестрой Джейн. Рассмотрим, однако,
пример простой базы данных языка Пролог, состоящей из фактов
"брат_или_сестра":
брат-или_сестра (джейн, элис).
брат _или—сестра (кэти, дорога).
Если написать запрос к этой базе данных, в котором аргументы распола-
располагаются в том же порядке, как и у фактов, входящих в эту базу, то запрос
будет успешным:
! ? — брат—или—сестра (джейн, элис).
да
Но если поменять аргументы местами, то запрос потерпит неудачу:
| ? - брат „или „сестра (элис, джейн).
нет
L ТИПЫ ОТНОШЕНИЙ 99
грицательный ответ на запрос свидетельствует о том, что приведенная
(есь реализация отношения "брат_или_сестра" несимметрична.
Определение симметричного отношения
Одним из способов придания симметрии предикату "брат_лли_сест-
i" может служить составление двух правил, ссылающихся на явную баау
щных. Явная база данных носит название "opaicecr". Она содержит нее
»едения о Джейн, Элис, Кэти и Дороги:
братсест (джейн, элис).
братсест(кэти, дороти).
брат_или_хестра2 (А, Б) : —братсест (А, Б). % A)
брат__или_сестра2 (А, Б) : - братсест (Б, А). % B)
равило A) предиката "брат_или_сестра2" передает аргументы А и Б
одцели "братсест" в том же порядке, как они заданы в заголовке правила.
равило B) меняет порядок следования аргумепюь. Запрос:
I-
I ? — брат_или_сестра2 (джейн, элис).
да
решается в соответствии с правилом A), а тот же самый запрос с обратным
Порядком следования аргументов:
! ? — брат_или_сестра2 (элис, джейн).
да
решается в соответствии с правилом B). Таким образом, предикат
?'брат_или_сестра2" ведет себя как симметричное отношение. Как Вы
таеге, какая совокупность ответов будет получена в результате ниже-
[едующего запроса?
? - брат_или._сестра2 (X, Y).
( Асимметрия
!;¦ Отношение, не обладающее симметрией, назьшается асимметричным.
Например, отношение между отцом и сыном является асимметричным.
Некоторые отношения, скажем, отношение любви одного лица к другому,
ре являются обязательно симметричными или обязательно несимметричны-
несимметричными. По умолчанию интерпретатор считает, что зее отношения асимметрич-
Ны, как это, к примеру, имело место для приведенного ранее отношения
брат_или_сестра".
Рефлексивность и нерефлексивность
Отношение, которое соблюдается, когда оба аргумента одинаковы,
называется рефлексивным. Отношения "равно" и "больше или равно"
являются примерами рефлексивных отношений. Отношение, которое на-
Таблица 1.1
Общеупотребительные отношения
бинарное
отношение
Свойства
симметрия
рефлек сивиость
транзитивность
Ограничение,
обеспечив ающее
целостность
меньше
равно
можно позвонить
брат или сестра
отец
предок
жена-
учитель
знает
асимметрично
симметрично
симметрично
симметрично
асимметрично
асимметрично
асимметрично
симметрично
нерефле ксивно
рефлексивно
нерефлексивно
нерефлексивно
нерефлексивно
нерефлексивно
нерефлексивно
нерефлексивно
транзитивно
транзитивно
ч
транзитивно
цетранзитивно
транзитивно
нетранзитивно
нетранзитивно
нетранзитивно
многие-к-многим
многие-к-многим
многие-к-многим
миогие-к-многим
один-к-многим
многие-к-многим
один-к-одному
многие-к-многим
миогие-к-многим
Z
S
ЕИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ 101
рушается, когда оба аргумента одинаковы, называется нерефлексивным.
"Выше" служит примером нерефлексивного отношения. По умолчанию
(нтерпретатор считает, что предикаты рефлексивны. Рассмотрим правило
^'конкурент", определенное ранее:
конкурент (К1,К2) : -
путешествие (К1, ГородА, ГородБ, _).
путешествие (К2, ГородА, ГородБ, _).
есь отсутствует условие, указывающее, что К1 должно отличаться от К2,
гому по умолчанию принимается, что правило "конкурент" рефлексив-
^. Тем самым при помощи правила "конкурент" можно доказать, что не-
торая транспортная компания является конкурентом сама себе:
? — конкурент (амтрак, амтрак).
да
от результат явно не имеет смысла, поэтому целесообразно переписать
вило "конкурент" так, чтобы оно стало нерефлексивным (см. разд. 4.1).
Транзитивность
Отношение между аргументами называется транзитивным, если оно
сохраняется при переходе от прямого отношения к косвенному. "Равно"
ркит примером транзитивного отношения: если А равно В, а В равно С,
и А должно быть равно С. "Выше" — еще один пример транзитивного
Ношения. В языке Пролог транзитивные отношения обычно реализуются
сурсивными процедурами, примерами которых могут служить процеду-
[ "предок" и "можно_путешествовать4".
Анализ общеупотребительных отношений
В табл. 1.1 представлены свойства и ограничения для некоторых обще-
общеупотребительных отношений.
БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ
К настоящему времени создано много синтаксических вариаций языка
Пролог. Помимо семейства версий Пролога, в которых авторы придержи-
придерживаются синтаксиса версии этого языка для ЭВМ DEC-10, существуют также
LM-Пролог [48], Ватерлоо Пролог [90], Пролог/KR [77], 1С-Пролог [19],
микро-Пролог [20], IBM Пролог и т.д. Каждая версия языка имеет свой
вариант синтаксиса. В настоящее время, однако, широко используются
только два варианта синтаксиса языка Пролог: DEC-10 Пролог и микро-
Пролог. Большинство пользователей работает с версиями Пролога, в кото-
которых употребляется DEC-10-синтаксис. Решение об использовании в данной
книге синтаксиса DEC-10 Пролога основывалось именно на этом чисто
<тическом соображении.
102 ГЛ. 1. ФАКТЫ И ИРАВИЛд
После осБиеиии основных концепций языка Пролог не представ^
Ci.jii лого труда перевести программу с одной версии синтаксиса Пролша
на другую. Можно даже составить Пролог-программу, которая будет вынол-
нлть такой перевод автоматически. Пример такой программы, выполняю-
выполняющей преобразование синтаксиса DCC-10-всрсии в иипаксисмикро-Проло».!.
приведен в гл. S,
Те читатели, которые ознакомились с разд 0.6, могут посчишгь, м,
при обсуждении квантификагии переменных в запросах язмка Пролог
(см. разд. 1.3) была допущена ошибка, В разд. 1.3 утверждается, что пере-
переменная Кто в запросе
i ? — знает (мэри, Кто).
квантифинируется экзистенциально. В разд. 0.6 же было сказано, что ъ<-
переменные во фразах Хорна неявным образом квантифицируются уы
версально. Запрос Пролога, подобный приведенному выше, можно рассма.
ривать как фразу Хорна, состоящую из одного условия без заключения.
Вспомните, что, в соответсгеии с материалом разд. 0:6 условиями во фразах
Хорна служат негативные атомарные формулы- В примере резолюции
нисходящим методом (см. разд. 0.6) фраза A4) (~Р(а)) также является
условием без заключения. Тогда запрос Пролога, приведенный выше
можно записать во фразовой форме следующим образом:
~знает (мэри, X)
или, делая квантификацию X явной,
VX ~знает(мэри,Х) A)
Это означает: для любого X Мэри не знает X или Мэри никого не знает.
При отрицании кваншфикация переменной всегда изменяется на про-
противоположную, поэтому формула A) логически эквивалентна формуле
~(ЭХ знает (мэри, X)) (.2)
Смысл этой формулы: не является истиной то, что существует такой
человек X, которого знает Мэри, или Мэри никого не знает. Обе при-
приведенные формулы отражают логический смысл запроса Пролоы. Запрос
лучше воспринимается в виде формулы B), в которой переменная кван-
тифицирована экзистенциально.
Типы отношений и ограничения, обеспечивающие целостность отно-
отношений, подробно рассматриваются в работе [88, с. 112—124].
УПРАЖНЕНИЯ
1. Запустите интерпретагор Пролога. Воспользуйтесь командой
"consult" для того, чтобы в диалоговом режиме ввести несколько фраз
со сведениями о Вашей семье, либо со сведениями из какой-нибудь
другой прикладной области, с которой Вы хорошо знакомы. Приду-
Я .ЖНЕНИЯ 103
манте запросы к этим фразам, используйте в этих запросах и констан-
и,), и переменные.
I. Воспользуйтесь редактором для создания текстового файла под
званием "путешествие". Внесите в этот файл приведенные в данной
йве факты "путешествие" и процедуры "можно „путешествовать" и
сонкурент". Запустите интерпретатор языка Пролог и загрузите этот
1Йл. Напишите запрос, в котором выясняется возможность путешест-
[я из Нью-Йорка в Бирлиигтон. Составьте, запрос, позволяющий полу-
ть сведения обо всех нарах компаний-конкурентов. Напишите запрос
возможности добраться самолетом из Канзас Сити в Нэшвил.
3. Создайте при помощи текстового редактора файл с Пролог-прог-
цшой, который называется "группа". Соберите сведения об именах
ших товарищей по учебе и внесите в программу факты, в каждом из
ггорых должны быть указаны имя студента и наименование группы или
ц<ультета, на котором этот студент числится. Например, Генри числится в
уппе по разработке сетей, Розмари - в группе сопровождения компиля-
ров и т.д.
Добавьте в программу правило, задающее условия, согласно которым
[Но лицо знает другое, если ош оба входят в состав одной и .ой же
уплы.
Загрузите написанную Вами программу. Напишите запросы, позволяю-
выяснить следующее. Кого знает Генри (или кто-то еще из Вашей прог-
ммы)? Кого знает кто-то?
Если программа не даст ожидаемых результатов, то вернитесь из среды
Ггерпретатора Пролога в текстовый редактор. Попытайтесь определить,
(чему программа не работает, и исправьте ошибку.
4. Как Вы считаете, симметрично ли отношение, в соответствии с кото-
»м одно лицо знает другое? Каким видом ограничения, обеспечивающего
постность, оно регулируется — один-к-одному, один-к-многим, многие-
одному или многие-к-многим? Как будет обстоять дело для только что
писанной Вами процедуры "знает"? Как можно было бы изменить проце-
РУ "знает", чтобы она стала соответствовать результатам Вашего анализа
Ношения "знает"?
5. Придумайте транзитивное отношение (похожее на "можно_путе-
!Ствовать4"), в котором имеется косвенная связь, например, связь по
авам собственности между компанией и компанией-держателем ее пакета
дай, или снабженческая связь между компанией-изготовителем и компа-
№й-поставщиком, производящей детали.
Напишите Пролог-программу, моделирующую это отиошеше, включая
е необходимые факты и правила. Протестируйте Вашу программу, чтобы
•сверить, выполняет ли она то, что было задумано,
6. Должна ли процедура "конкурент" быть симметричной? Является
она симметричной?
104 ГЛ. 1. ФАКТЫ И ПРАВИЛА
7. Приступите к разработке своей собственной программы "советник
по транспорту". Выберите либо сеть, состояшую из городов, либо транс-
транспортную сеть маршрутов поездов или автобусов в пределах одного города.
Вы должны информировать систему о том, откуда и куда Вы собираетесь
добраться, а система должна выдавать рекомендации о том, какими
поездами, автобусами, самолетами и т.д. Вам следует воспользоваться,
чтобы добраться до пункта назначения.
ГЛАВА 2
АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
2.1. АРИФМЕТИКА
Арифметические выражения
В языке Пролог имеется ряд встроенных предикатов, предназначенных
пя вычисления арифметических выражений. (Встроенный предикат - это
зцедура, входящая в систему программного обеспечения интерпретатора
Jtponora.) В Прологе арифметические выражения вычисляются только
огда, когда они служат аргументами одного из таких встроенных пре-
якатов.
Арифметическое выражение состоит из целых чисел, например:
10 -3 2000
из нижеследующего множества операций:
+ - * / mod.
а исключением унарной операции "минус", все операции языка Пролог
цляются инфиксными. У инфиксной операции — два аргумента, а обозна-
Жие операции записывается между этими аргументами без употребления
кобок. В приводимом ниже списке X и Y обозначают либо числа, либо
(ругие арифметические выражения.
t>
? Арифметические операции
; x + y .
• X-Y
> X ¦ Y ¦
-X .
X/Y
; X mod Y
Примечание: в некоторых версиях языка Пролог имеются также числа с
плавающей точкой н арифметическая операция //, предназначенная для
выполнения целочисленного деления (см. приложение IV).
106 ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
Предикат "is"
В языке Пролог имеется встроенный предикат "is'" (есть), являющий-
являющийся также инфиксной операцией. Первым аргументом здесь служит некон-
кретизированная переменная или целое число, а вторым аргументом -
арифметическое выражение, не содержащее неконкретизированных пере-
переменных. Предикат "is" унифицирует первый аргумент с результатом Вы-
Вычисления второго аргумента.
; ?-Yis 10*4. IV
У = 40
| ? _ 40 is 10 * 4. . - ¦ ?
да
! ? - X is 50, YisX/2.
Х = 50
У* 25
! ? - X is.?. YisE*X)/2.
нет i
. Предикат "is"является детерминированным
Последний пример показывает, что предикат "/*" даст максимумами
ответ. Предикат, вырабатывающий только один ответ, называется deftp-
минированным
Предикаты, выполняющие сравнение :
Приводимые ниже предикаты предназначены для пниолнения операции
арифметического сравнения. У каждого из них в качестве аргументов долж-
должны выступать арифметические выражения. Эти аргументы вычисляются
перед выполнением сравнения.
> больше
< меньше
> = больше или равно
- < меньше или равно
- : = равно
- \ ¦* не равно
Данные предикаты можно употреблять таким образом:
] ? — 12 = <.' 24
да
\ 7 - 50 = \ = 50.
нет
1.1 СТРУКТУРЫ ДАННЫХ
107
Виды связи аргументов
Считается, что аргумент, входящий в запрос, является для процедуры
входным, если он представляет из себя атом или структуру. Аргумент
считается выходным для процедуры, если он является переменной. Аргу-
Аргумент называется двунаправленным, если в запросе к процедуре его можно
Использовать или как входной, или как выходной. Все правила и
:ты, рассмотренные в гл. 1, являются целиком двунаправленными.
Однако встроенные предикаты, предназначенные для выполнения
ифметического сравнения, не являются двунаправленными. В mix каж-
аргумент должен представлять us себя арифметическое выражение,
(.состав которого не входят неконкретизированные переменные. Если в
|честве одногс из Ергумениж этих предикатив будат задана леконкрети-
ованная переменная, то шиерпрета^р выдаст сообщение об ошибке.
2.2. СТРУКТУРЫ ДАННЫХ
Типы термов
Аргументы фраз Пролога называются термами. Существует три типа
рмов:
Константа
Атом ^записываемый как слово, начинающееся с ма-
маленькой буквы, либо как произвольная группа симво-
символов, заключенная в апострофы) или шмос число.
Переменна! Записывается как слово, начинающееся с большой бух-
• т»ы, или как слово, начинающееся с симвочя .., или сам
символ ....
Составной
терм
(или
структура)
Записывается как
ямя(.арг1 аргп), i де aprl,.. . , аргп сами являются
термами.
Сходство составных термов с записями
Читатели, которые знакомы с языками Си или Ик.калъ, обнаружат,
• i составные термы языка Пролог аналогичны записям Па»аля пяч
Фуктурам Си, т.е. составные аермы -- это определяемые ирограммисюч
чбьекты произвольной скожносги. Если придерживаться данной аналогии,
го имя и количество аргументов составного терма показывают тип записи,
•1 аргументы составного терма соответствуют полям записи. Неформальный
¦ рмин структура означает то же самое, что и составной терм.
108 ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
Примеры составных термов
Структура "клиент", приводимая ниже, содержит информацию о клиен-
клиенте, берущем автомашину напрокат. В этой структуре содержатся сведения
о фамилии, суточном тарифе и о количестве дней, на которое взята машина.
Структура "дата" содержит данные о годе, месяце и дне. Обе структуры
служат аргументами факта "сделка":
сделка (клиент (смит,29,4), дата (86,4,22) ).
Факт "сделка" связывает информацию о сделке с клиентом и дату, когда
эта сделка была заключена. Примечание: принято, что структуры записы-
записываются без пробелов между аргументами, а факты, правила, подцели и за-
запросы записываются по крайней мере с одним пробелом между аргумен-
аргументами *),
Правило;в соответствии с которым вычисляется
общая сумма оплаты
Ниже приводится правило, в котором аргументом служит структура
"клиент", а в результате обработки правила подсчитывается общая сумма,
которую должен заплатить клиент (т.е. суточный тариф, помноженный на
количество дней): i
% + - |
итого (клиент (_,Тариф,Дни), Сумма) : — I
Сумма is Тариф * Дни.
Строка комментария, расположенная над правилом, следует соглашению,
по которому входные аргументы помечаются в комментариях знаком +,
а выходные аргументы помечаются знаком —. Здесь входным аргументом
правила "итого/2" является структура "клиент", а выходным — перемен-
переменная "Сумма". Фамилия клиента не требуется для вычисления суммы опла-
оплаты, поэтому первый аргумент структуры "клиент" обозначен символом
Запрос к правилу "итого"
Запрос к правилу "итого" можно записать так:
! ? - итого (клиент ('Б. Смит',29,4), С).
С =116
Как Вы считаете, что произойдет, если написать запрос, в котором либо
переменная «Тариф)), либо переменная «Дни» будет неконкретизиро-
ванной?
Рекурсивные структуры
Использование структур языка Пролог в большинстве случаев анало-
аналогично применению структур языка Си. К примеру, одним нз способов пред-
представления в памяти ЭВМ записей базы данных является использование
•)в переводе это правило не всегда соблюдается. - Примеч. пер.
2.2. СТРУКТУРЫ ДАННЫХ 109
рекурсивных структур (аналогичных односвязным спискам — см. работу
[2]), в которых один из .аргументов каждой записи указывает на сле-
следующую запись. Для того чтобы на языке Пролог создать рекурсивную
структуру, состоящую из записей "клиент", единственное, что нужно —
это добавить в структуру "клиент" дополнительный аргумент, указы-
указывающий на следующую запись. Ниже приводится рекурсивная версия
структуры "клиент", названная "кл":
кл (смит,29,4, кл(джонс,40,5, кл (ли,29,1 ,end)))
1-я запись 2-я запись 3-я запись
Заметьте, что уровень вложенности у каждой новой записи будет боль-
большим, чем у предыдущей. В четвертом поле последней записи, входящей
!> данную рекурсивную структуру, содержимся слово «end», обозначаю-
обозначающее, что больше записей нет.
Работать с рекурсивными структурами языка Пролог несколько
легче, чем со связными списками языков программирования, подобных
языку Си. Дело в том, что интерпретатор Пролога берет-на себя все дейст-
действия, связанные с обработкой указателей.
Процедура, которая строит рекурсивную структуру
Рекурсивные структуры могут использоваться для описания различных
видов сложных взаимосвязей между термами. Примером этого может слу-
служить рекурсивная процедура "можно_путешествовать5", во многом похо-
похожая на процедуру "можно—путешествовать4". В процедуре "можно_путе-
шествовать5" строится рекурсивная структура "путь/3", описывающая
все промежуточные пункты, посещаемые по пути из исходного города в
пункт назначения.
% компания отправление прибытие вид транспорта
путешествие (амтрак, нью_йорк, бостон, поезд),
путешествие (ндж_транзит, нью_йорк, принсгон, поезд).
путешествие (амтрак, бостон, Портленд, поезд),
путешествие (грейхаунд, бостон, портленд, автобус),
путешествие (амтрак, нью_йорк, Вашингтон, поезд),
путешествие(пиплз, нью_йорк, Вашингтон, самолет),
путешествие(пиплз, бирлингтон, нью_йорк, самолет).
можно_путешествовать5 (А, Б, путь(А,Вндтраис,Б)) : —
путешествие (_, А, Б, Видтранс).
можно_путешествовать5 (А, Б,путь(А,Видтранс,Рпуть) ) :-
путешествие (_, А, В, Видтранс),
можно_путешествовать5 (В, Б, Рпуть).
110 ГЛ.2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
Запросы к процедуре "можно-,путешествовать5"
На примере следующих запросов можно проиллюстрировать пользо-
пользование процедурой "можно_пушествовать5".
! ? - можно_путешестпопать5 (нью _йорк, бостон, П).
// = путь («ьм йорк,ппезд,бостон)
Ответ на этот запрос показывает, что существует прямой маршрут ("путь")
поездом из Нью-Йорка в Бостон. р«.
| ? - можно_-путешсчповать5 (нькк_йорк, портленд, П). Щ
П = путь (нью-йорх.псезд, fs/
путь {бостон,поезд,портленд));
П--путь {нью _йорк,поезд,
путь(бостон,автобус, портягнд))
\ ? — можно„ путешествовать5 (бирлингтон, портленд, П).
П = путь(бирлингтон.самолет, ..
путь {нью—йорк,поезд,
путь (бостон, поезд, портл енд) ) )
Ответ на последний запрос показывает, что существует маршрут из Бир-
линггона в Портленд через Нью-Йорк и Бостон.
2.3. СПИСКИ
Представление списков при помощи структуры "./2"
"./2" — это специальная рекурсивная структура, используемая для
представления списков произвольной длины. У этой структуры имеется два
apryiwcirra. Первым аргументом является терм любого вида, а вторым —
ялбо другая структурч "./2", либо сочетание символов [], которое обозна-
обозначает конец списка.
Нижеследующая структура представляет собой список, состоящий из
одного элемента — атома « кетлин>>:
. (кетлин, [ ])
В следующем примере представлен список, состоящий из трех элементов —
« альфа />,« бета » и <' гамма »:
(альфа,, (бета,, (гаммэ, [•])))
Другая форма представления списка,
в которой употребляются квадратные скобки
Запись списков в виде структуры "./2" является громоздкой, поэтому
существует иная форма представления списков. Элементы списка распо-
располагаются между квадратными скобками и отделяются друг от друга запя-
запятыми. При такой форме записи два списка, представленные выше, при-
? 3. СПИСКИ til
:твид:
[кетлин] ; •
[альфа.бета, гамма]
'п.метьте, что здесь нет надобности явно указывать конец списка при помо-
yi символов [J. Форма записи списков с использованием квадратных
'.об^к и представление списков в виде структуры "./2"полностьювзаимо-
(меняемы-
Представление списков произвольной длины
Предположим, что нужно представить список, в котором первые два
элемента известны, а количество остальных элементов не определено.
Такой список можно представить в виде структуры "./2", если в качестве
второго аргумента структуры "./2" с наибольшим уровнем вложенности
взять неконкретизированную неременную:
. (один,, (два,X))
Здесь наиболее глубоко вложенной "./2"-структурой является структура
<< .(два.А')», поэтому общая длина списка будет зависеть от значения пе-
переменной X Если
то общая длина списка будет равна двум, а если
X - . (три, . (четыре, . (пяп>, [ ])))
ти длина получившеюся описка будет равна пячи.
Список произвольной дчины при использовании формы записи
с квадра 1БЫМ11 скобками
Существует эквивалентный способ представления списков неопреде-
неопределенной длины, при котором употребляется форма записи с квадратными
скобками. Для том чтоб!-; отделить конкретные элементы, образующие
начальную часть списка, от переменной, представляю-цей оставшуюся часть
этого списка, применяется символ !. Предыдущий пример при употребле-
употреблении такой формы обозначения примет вид:
[одиндва' X]
Начало и остаток списка
Символ | разделяет список на две части: иа начало списка, которое об-
образуют все элементы, стоящие перед символом i (в данном случае — эле-
элементы «один» и «два»), и остаток списка, обозначенный некоторой
неременной (в данном случае X). Начало списка всегда представляется в
явном виде, а остаток — в неявном виде при помощи переменной, раепо-
112 ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
ложенной справа от символа ;.
Если ,
Х=[] •>
то длина получившегося списка будет равна двум, а если \t'
X = [три, четыре, пять] ?
то длина результирующего списка станет равна пяти. lv
При любой из двух форм записи сочетание символов [] обозначат
пустой список. ;'<,,
Примеры списков
Ниже приводятся примеры списков в форме записи с квадратными
скобками. Во втором примере дан список структур "телефон/2". В послед-
последнем примере показано, что элемент списка может сам быть списком.
[представление, для, фразы]
[телефон (джонс, 7279112), телефон (родригес, 9421001)]
[Первый | Остаток]
[[а, Ь, с], [1,2] |R]
Встроенный предикат "="
Встроенный предикат "=", имеющий два аргумента, записывается в ин-
инфиксной форме записи. Этот предикат проверяет, унифицируются ли друг
с другом его аргументы. Если в одном из аргументов содержатся неконкре-
тизированные переменные, то в случае успешной унификации они конкре-
конкретизируются. Предикат *'=" используется в приводимых ниже списках для
того, чтобы продемонстрировать выполнение проверки совпадения с эта-
эталоном. Вначале, однако, рассмотрим запросы, иллюстрирующие примене-
применение предиката "=" для работы с несписковыми аргументами.
% унифицировать переменную X с "привет":
! ? - X = привет.
X= привет
% проверить, унифицируется ли "привет" с "до—свидания":
! ? — привет = до_свидания.
нет
% унифицировать две структуры "клиент":
] ? -клиент(смит,29,4) = клиент(X, Y, Z).
Х= смит
Y=29
Z = 4
|СПИСКИ 113
Унификация списков
Если воспользоваться формой записи списков с употреблением квдд-
скобок, то легко можно выделить произвольное количество эле-
нтов, стоящих в начале списка. Далее показаны запросы, демонстрирую-
унификацию различных списков.
% выделить первый элемент списка:
! ? - [F J R] =[1,2, 3,4, 5].
F=l
R = [2, 3, 4, 5}
! 9 - [F ,' R] = [а].
F = a
% взять первые два элемента списка:
i ?- [F1.F2IR] = [a.b.c.d].
Fl = a
F2 = b
R=fc.dJ
1 '- [F1,F2!R] = [a].
нет
рследний запрос терпит неудачу ввиду того, что список [Fl, F2] R] будет
гасовыьаться только со списками, содержащими два или более элемен-
в списке [а] содержится лишь один элемент.
Сравнение списков и простых структур
[Сто одну и ту же информацию можно одинаково хорошо представить
иде списка, и в виде простой структуры. К примеру, два представле-
юва и его перевода в словаре могут выглядеть так:
[цветок, flower] представление в виде списка
(цветок, flower) представление в виде структуры
(ел обозначает словарь)
С точки зрения хорошего стиля программирования в тех случаях, когда
количество элементов фиксированно, рекомендуется пользоваться про-
простыми структурами. В приведенном выше примере в каждой позиции сло-
словаря будет только по два элемента, поэтому структура "ел" лучше подхо-
Дит ,пя представления этой информации. Списками лучше пользоваться
, когда количество элементов заранее неизвестно.
114 ГЛ.2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЬц
2.4. ПРОЦЕДУРЫ, ВЫПОЛНЯЮЩИЕ ДЕЙСТВИЯ СО СПИСКАМИ
Применение рекурсивных процедур для обработки списков
Рекурсивные процедуры служат наиболее удобным средством для вы.,
полнения действий с каждым из элементов списка. Рекурсивная проце.
дура может работать со списком любой длины, что освобождает програ^.
миста от необходимости заранее знать точную длину обрабатываемого
списка. Рекурсивная процедура, выполняющая обработку списков, имеет
ту же общую структуру, что и любые другие рекурсивные процедуры
Вначале располагаются фразы, определяющие условия окончания рекур.
сии, а затем следует фраза, выполняющая действия с заголовком списка,
которая далее вызывает рекурсивно сама себя с аргументом, которым
служит остаток списка.
Процедура, предназначенная для вывода на печать
всех элементов списка
Примером простой процедуры, выполняющей обработку списка, р
жст служить процедура "печатать_злсменты". Единственным аргумент
этой процедуры является список. Процедура выводит на печать все j
менты заданного списка. Здесь "write" (вывести) - это встроенный и
дикат, который выводит на терминал значение своего аргумента. Встро
ный предикат "nl" выполняет возврат каретки и перевод строки (т.е. i
реход к началу следующей строки).
% исходный вид процедуры при пустом списке
печатать_элементы ([ ] ). % A)
% рекурсивное праиило.
печатать^элементы ([Первый; Остаток]) :- % B)
write (Первый), nl, % вывод первого элемента
печатать—элементы (Остаток).% рекурсивный вызов .
Использование процедуры "печатать—элементы" можно проиллюстриро
вать на примере следующих запросов:
| ?-псчатать_элементы ([один, путь (рэлей, нэшвилл)]).
один
путь (рэлей, нэшвилл)
да
! ?—печзтать_элемеиты ( [а, Ь, с] ). .
а
b
с
да
f ПРОЦЕДУРЫ, ВЫПОЛНЯЮЩИЕ ДЕЙСТВИЯ СО СПИСКАМИ
115
печатать_элементы
ФразаB.)
печатать_элементы ( [й,с] ) I
ФразаB)
печатать_злементы ([с])
Фраза B)
печатать_элементы ( [ ])
Рис. 2.1
Фраза A)
Выполнение запроса к процедуре "печатать_элемеиты'>
= Выполнение предыдущего запроса можно рассматривать как после-
ателыюсть вложенных вызовов процедуры "печатать_элементы",
|чем при каждом последующем вызове этой процедуры список будет
оче, чем при предыдущем. Дерево доказательства, приведенное на
2.1, показывает, как при каждом последующем вызове процедуры
атать_элементы" список, являющийся ее аргументом, сокращается.
Заметьте, что рекурсия прекращается при достижении процедурой
иатать__элементы" пустого списка, т.е. [ ].
Печать списка в обратном порядке
Процедура "обр-печать" почти идентична процедуре "печатать_зле-
менты". Отличие состоит в том, что "обр_печать" выводит элементы
списка на печать в обратном порядке. Это достигается за счет изменения
Порядка следования подцелей в рекурсивном правиле, так что процедура
становится леворекурсивной.
' % условие окончания, когда список пуст.
|обр__печать ([]). % A)
I % рекурсивное правило.
обр_печать ([Первый | Остаток]) :- % B)
обр_печать (Остаток), % рекурсивный вызов
write (Первый), nl. % вывод первого элемента
116
ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
обр _ печать (,[а,Ь, о ] )
Фраза B)
Фраза B)
Фраза A)
Рис. 2.2
| ?- обр_печать ([а, Ь, с]).
с
Ь
а
да
На рис. 2.2 изображено дерево доказательства, соответствующее этому
запросу.
Форма записи аргументов в заголовке правила
Форма записи аргументов в заголовке правила определяет обстоятель-
обстоятельства, при которых оно будет действовать, поскольку заголовок правила
должен быть унифицирован с запросом до того, как интерпретатор пред-
предпримет попытку обработки тела правила. Например, аргумент в первом
правиле процедуры "печатать_элемеиты" будет унифицироваться только
с пустым списком. Аргумент второго правила будет унифицироваться
только со списком, содержащим не менее одного элемента (например,
sneivscHT « Первый »). Поэтому интерпретатор не будет обрабатывать второе
правило, если аргументом служит пустой список.
В практике программироваиия рекомендуется использовать в заголов-
заголовках правил такие формы записи аргументов, которые будут указывать
на обстоятельства применения данных правил. Это будет способствовать
более эффективной работе процедур.
2.4 ПРОЦЕДУРЫ, ВЫПОЛНЯЮЩИЕ ДЕЙСТВИЯ СО СПИСКАМИ 117
Примеры процедур, преднаэиачеиных для обработки списков
Процедура "элемент" имеет два аргумента. Вторым аргументом про-
процедуры является список. Запрос к процедуре "элемент" даст положитель-
положительный результат, если в качестве первого аргумента будет задан элемент,
входящий в список.
Процедура "элемент"
^ % исходный случай: X является первым элементом списка.
элемент (X, [X \ Остаток] ). % A)
% X не является первым элементом списка, искать X в
% оставшейся части списка.
элемент (X. [Y \ Остаток]) :- % B)
элемент (X, Остаток).
% входит ли элемент b в список [а, Ь, с] ?
! ?- элемент (b, [a, b, с] ).
да
! ?— элемент (b, b).
нет
% выдать элементы списка:
! ?- элемент (X, [1,2,3]).
Х=1\
Х=2;
Х=3\
• нет
Заметьте, что первым аргументом последнего запроса является перемен-
переменная, которая поддается унификации со всем, что угодно. Этот запрос к
процедуре "элемент" позволяет получить значения всех элементов списка,
являющегося вторым аргументом процедуры.
Процедура "найти-слово"
Процедура "найти_слово" похожа на процедуру "элемент". Различие
между ними заключается в том, что процедура "найти_слово" заканчи-
заканчивается либо когда список пуст, либо когда атом обнаружен в списке. Об-
Обратите внимание, как форма записи аргументов в заголовке каждой фразы
используется для указания обстоятельств применения этой фразы.
% исходный случай № 1: список пуст
найти_слово (Слово, [ ]) :- % (!)
write (Слово),
write (' не найдено '), nl.
118 ГЛ.2. АРИФМРТИКЛ И СТРУКТУРЫ ДАННЫХ
% исходный случай № 2: переменная Слово унифицируется
% с первым элементом списка
найти_слово (Слово, [Слово ] Остаток] ) % B)
% рекурсия, если переменная Слово не унифицируется с
% первым элементом списка
найти_слово (Слово, [Хслово ! Остаток]) :- % C)
найти-слово (Слово, Остаток).
Примеры запросов к процедуре "найти—слово".
\ 1— найти_слово (в, [находится, в, доме]).
да
\ ?-найти_слово (коровник, [находится,в,домс] ).
коровник не найдено
да
\ ?—найти_слово (X, [находится,в,доме]).
X = находится;
Х= доме
Как Вы считаете, какой ответ выдаст интерпретатор, если пользовать
еще раз введет символ ; ?
Процедура "присоединить"
Все три аргумента процедуры "присоединить" являются ^писками.
Списки, задаваемые в первых двух аргументах, объединяются в один спи-
список, возвращаемый через третий аргумент. Процедуру "присоединить"
можно также использовать для разбиения списка, представленного чретьим
аргументом, на два подсписка. Процедура "присоединит*." называется
обратимой, так как все три ее аргумента — двунаправленные.
% исходный случай: первый аргумент — пустой список
присоединить ([],Список, Список). % (!)
% Взять элемент 1 из начала первого аргумента и поместить
% его в начало третьего аргумента, либо выполнить обраг-
%ное действие:
присоединить ([X ! Список1], Список2, [X ! СписокЗ]) :- % (Г '
присоединить (Список!, Список2, СписокЗ).
p
.ПРОЦЕДУРЫ, ВЫПОЛНЯЮЩИЕ ДЕЙСТВИЯ СО СПИСКАМИ
119
; ?-присоединить ([а, Ь, с], [1, 2], Y).
Y=[a,b,c, 1,21
\ ?- Присоединить ([a], X, [a, z, m, n] ).
X = [z, m, n/
I?-присоединить (А, В, [1,2,3]).
I B =[1.2, 31;
A-[11
B"[2.3J;
\A=[1,21
В 431,
A 41,2,3/
нет
атите внимание, что в результате последнего чапроса были сгенериро-
вге возможные способы разбиения списка [1, 2, 3] на два подсписка.
Процедура "длина"
Первым аргументом процедуры "длина" является список, а через вто-
I аргумент даннля процедура возвращает длину этого списка.
% исходный случай - в пустом списке нуль элементов.
длина ([].О). % A)
длина ([Г I R], N) :- % B)
дайна (R, N1),
NisNl+ 1.
! ?-длина ([альфа,беТа,гамма],Дп).
;¦ Дл - 3
. | ?- длина ([[а,Ь1,Х],Дл).
етьте, что в последнем запросе список [а, Ь] считается одним элемен-
[ и неконкретизированная переменная X также считается одним элемен-
'$; _ 1 - это внутреннее обозначение переменной X. Оно выводится на
ть, так как в точке получения позитивного ответа на запрос перемен-
X не конкретизирована. Программист не может пользоваться таким
fренним обозначением для обращения к переменной.
120 ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫ>
2.5. СПОСОБЫ ПРЕДСТАВЛЕНИЯ БАЗЫ ДАННЫХ
Пять способов представлении
Существует несколько видов представления базы данных в языке
Пролог. Перечислим их:
!) множество фактов, каждый из которых соответствует целостному
информационному элементу *) (т.е. записи) базы данных;
2) множество фактов, каждый из которых соответствует паре значе-
значений атрибут/ключ;
3) список структур, в котором каждая структура соответствует за-
записи базы данных;
4) линейная рекурсивная структура, где каждая структура соответ-
соответствует записи базы данных, к примеру, структура "кл/4";
5) рекурсивная структура в виде двоичного дерева, в которой ка»
дый узел дерева соответствует записи базы данных.
В оставшейся части раздела показано представление базы данных "служа-
"служащий/4" каждым из пяти названных способов. Для каждого'представления
приводится запрос, позволяющий найти всех служащих отдела 100.
1) Представление целостных информационных элементов в виде фактов
Простейшим способом представления базы данных в язке Пролог
служит запись каждого целостного информационного элемента в виде
факта:
% Имя Отд. Должность Оклад
служащий! (брайен, 100, оператор, 20000).
служащий1 (нэнси, 200, начальник, 71000). (
служащий1 (ральф, 100, менеджер, 71500).
Нижеследующий запрос позволяет отыскать всех служащих отдела 100:
! ?- служащий 1 (И, 100, Д, О).
И= брайен
Д=оператор
О =¦¦ 20000;
И = рсигьф
Д = менеджер
О =71500;
нет
2) Представление атрибутов в виде фактов
Вместо того, чтобы записывать факты, содержащие целостные ин
формациошче элементы, можно использовать в качестве фактов отдель
*) В оригинале - "tuple". - Примеч. пер.
2.Ь. СПОСОБЫ ПРЕДСТАВЛЕНИЯ БАЗЫ ДАННЫХ 121
ныс атрибуты (т.е. свойства) этих информационных элементов. В случае
необходимости данные атрибуты можно собрать в единое целое при по-
полоши правила. Один из атрибутов должен выступать в роли ключа, объеди-
объединяющего все остальные свойства. Атрибут "имя" можно использовать в
качестве ключа для базы данных "служащий". Первый целостный инфор-
информационный эпемеит "служащий" можно представить таким образом:
• ндел (брайен, 100),
должность (брайен,оператор).
оклад (брайен, 20000).
! атрибуты служащего можно объединить при помощи правила:
служчщий2 (Имя, Отд, Долж, Окл) :¦-
отдел (Имя, Отд),
должность (Имя, Долж),
оклад (Имя, Окл).
правило определяет неявную базу данных того же вида, что и приве-
мая ранее явная база данных "служащий1". Для такого правила можно
олыюваться предыдущим запросом, который даст те же результаты,
iи ранее:
?- служащий2 (И, 100, Д, О).
И= брайен
[ Д = оператор
) О = 20000;
= ральф
\Д = менеджер
0 = 71500;
нет
Применение атрибутов является более гибким средством представления
базы данных, чем применение целостных информационных элементов,
поскольку новые атрибуты можно, добавлять без переписывания заново
всей существующей базы данных. Приведем пример правила, в котором
предписывается выдача премии в 1000 долл. всем служащим отдела 200.
Это описывается при помощи атрибута "премия":
премия (Имя, 1000) :- отдел (Имя, 200).
1 некоторых служащих можно ввести атрибут "стаж_работы":
Рстаж-работы (брайен, 2).
tстаж_.работы (нэнси, 1).
вление новых атрибутов "премия" и "стаж_работы" никак не повлия-
i приведенное выше правило "служащий2".
122 ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
3) Представление в виде списка структур
Базу данных можно также считать потоком целостных информацион-
информационных элементов, что представляется на языке Пролог в виде списка струк-
структур. Каждый элемент списка — это целостный информационный элемент:
% Имя Отд. Должность Оклад
[ел (брайен, 100, оператор, 20000), Г
ел (нэнси, 200, начальник, 71000), |'
ел (ральф, 100, менеджер, 71500)]
Интересно отметить, что при таком подходе к структуре базы данных
поток целостных информационных элементов не нужно включать в те-
текущую программу. Он может существовать лишь как аргумент запроса,
входящий в различные подцели, которые обрабатывают этот поток.
В следующей процедуре входным является второй аргумент. Этот
аргумент содержит список целостных информационных элементов. Ре-
Результат выполнения процедуры возвращается через ее первый аргумент >-
по одному целостному информационному элементу за один ответ на запрос.
% выдается целостный информационный элемент, стоящий
% в начале списка.
% - +
один_циэ_1 (сл(Имя,ОтдДолж,Окл), [сл(Имя,ОтдДолзж,Окл)|
Остаток]).
% игнорировать целостный информационный элемент, стоящий в начале
% списка и вызвать процедуру "один_циэ_1" для получения следующе-
% го информационного элемента
один_циэ_1 (ел (Имя,Отд,Долж,Окл), [ел (_,_,_,_)!Остаток]) :—
один__циэ_1 (ел (Имя, ОтдДолж.Окл), Остаток).
С учетом этого определения процедуры "один_циэ„1" можно составить
запрос обо всех служащих отдела 100. Во втором аргументе этого запроса
полностью содержится вся база данных,
; ?- один_циэ_Л (сл(Имя,100, Долж.Окл),
[ел (брайен,100,оператор,20000),
ел (нэнси,200,начальник,71000),
ел (ральф,1ОО,менеджер,715ОО) ]).
Имя = брайен
Долж = оператор
Окл = 20000;
Имя = ральф
Долж = менеджер
Окл = 71500;
нет
2.5. СПОСОБЫ ПРЕДСТАВЛЕНИЯ БАЗЫ ДАННЫХ 123
4) Представление в виде рекурсивной структуры
Одним из вариантов представления базы данных в виде списка струк-
структур является представление в форме рекурсивной структуры, примером
которой может служить структура "кл" из разд. 2.2. Структуру "сл/4",
показанную выше, можно преобразовать в рекурсивную структуру ("рс")
nyicM добавления дополнительного аргумента, содержащего оставшуюся
ь базь; данных.
% Имя Отд. Должн. Оклад Ост. часть базы данных
рс(брайен,100,оператор,20000,
рс(нэнси,2ОО.начальник,71ООО,
рс (ральф,100,менеджер,715OO,end) ) )
жведем далее вариант процедуры "один_циэ", которая модифициро-
на таким образом, чтобы стала возможной обработка рекурсивной
руктуры. Первым (выходным) аргументом получившейся процедуры
дин_циэ_рс" является структура "сл/4".
% построить структуру "ел" из верхнего уровня рекурсивной структуры
% данных:
рдин_.циэ_рс (ел (Имя,Отч,Долж,0кл), рс(Имя,Отд,Долж,Окл,
Остаток)).
% игнорировать верхний уровень рекурсивной структуры, вызвать
% процедуру "один_„ци;)_рс" для получения следующего целостного
% информационного элемента из переменной Остаток:
один_циэ_рс (сл(Имя,ОтдДолж,Окл), рс(_,_,_,_, Остаток)) :—
один_циэ_рс (ел (Имя.Отд, Долж,Окл), Остаток) .
Опять-таки, после определения процедуры "один_циэ_рс" можно напи-
написать запрос, при помощи которого отыскиваются все служащие отдела 100.
Вторым аргументом процедуры "один_циэ_рс" является целиком вся
6ача данных.
! ?— один_циэ__рс (ел (Имя,100, Долж,Окл),
рс (брайен,100,оператор,20000,
рс (нэнсн,200,начальник,71000,
рс(ральф,1ОО,менеджер,715ОО,еп<1))).
Имя - брайен
Долж = оператор
Окл=20000;
- Имя = ральф
1Долж = менеджер
§' Окл = 71500;
нет
124 ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
5) Представление в виде двоичного дерева
Можно еще более усовершенствовать метод представления данных
в виде рекурсивной структуры, если преобразовать структуру "рс" в дво-
ичное дерево ("дд"). Это достигается путем введения одного дополни-
дополнительного аргумента. Смысл использования двоичного дерева заключается
в том, чтобы хранить базу данных в отсортированном виде. В приводимом
( брайен j ^ ральф
Рис. 2.3 <
ниже примере база данных отсортирована по атрибуту, описывающему-;
имя служащего. 1
Теперь в структуре будет шесть аргументов:
дд(Имя,Отд,Долж,Окл,Предыдущ,Последующ)
Переменная <( Предыдущ» описывает ветвь дерева, содержащую все це-
целостные информационные элементы, стоящие (в соответствии с алфавит-
алфавитным порядком) перед текущим элементом. Переменная « Последующ »
представляет ветвь, охватывающую все целостные информационные эле-
элементы, расположенные, согласно алфавиту, после данного элемента. Пред-
Предположим, что целостный информационный элемент, содержащий все све-
сведения о Нэнси, является самым верхним узлом дерева. Тогда двоичное
дерево, отсортированное в алфавитном порядке по именам служащих,
примет вид, изображенный на рис. 2.3. Это можно записать следующим об-
образом:
дд (нэнси ,200,начал ьник ,71000,
дд(брайен,100,оператор,20000,епё,еиё),
дд (ральф, 1ОО,меиеджер,715ОО,еп<1,еп<1)
)
Версия процедуры "один_циэ" для представления данных в виде дво-
двоичного дерева будет иметь вид:
% игнорировать верхний уровень двоичного дерева; вызвать про-
%цедуру "один_циэ_дд" для получения следующего целостного
% информационного элемента в соответствии со значением переменной
% Предыдущ:
. СПОСОБЫ ПРЕДСТАВЛЕНИЯ БАЗЫ ДАННЫХ 125
. один_циэ_дд(сл(Имя,Отд,Долж,Окл), дд (_,_,_,_, Предыдущ,
Последующ))
:— один_циэ_дд (ел (Имя,ОтдДолж,Окл), Предыдущ).
% выдать целостный информационный элемент, расположенный на
% верхнем уровне двоичного дерева:
один_циэ_дд (ел (Имя,Отд,Долж,Окл),дд(Имя,Отд.Долж,Окл, _,_)).
% игнорировать верхний уровень двоичного дерева; вызвать про-
% цедуру "один_циэ_дд" для получения следующего целостного
% информационного элемента в соответствии со значением переменной
% Последующ:
один_циэ_дд (сл(Имя,Отд,Долж,Окл), дц (_,_.,_,-.Предыдущ,
Последующ))
:- один_циэ_дд (ел (Имя,Отд,Долж,Окл), Последующ).
Теперь процедура "один_циэ_дд" определена, можно написать запрос,
позволяющий найти всех служащих отдела 100. Вторым аргументом запро-
запроса является целиком вся база данных.
! ?- один_циэ_дд (сл(Имя,100Долж,Окл),
|дд (нэнси,200,начальник ,71000,
дд (брайен,100,onepaTop,20000,end,end).
дд(ральф,ШО,менеджер,715ОО,епA,епс1)
L
щмя = брайен
Долж = оператор
Окл = 20000;
Имя = ральф
Долж = менеджер
Окл = 71500;
нет
Свойства представления в виде двоичного дерева
Одним из интересных свойств представления в виде двоичного дерева
является то, что процедура "один_циэ_дд" всегда будет выдавать целост-
целостные информационные элементы, образующие дерево, в отсортированном
"орядке. Это иллюстрирует запрос:
! 9— один_циэ_дд (Запись,
дд (нэнси,200,начальник ,71000,
дд (брайен, 100,onepaTop,20000,end,end),
дд (ральф, 100,менеджер,71500.end.end)
)
126 . ТЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЫХ
Запись = ел (брайен,100,оператор,20000) ;
Запись = ел (нэнси,200,начальник,71000);
Запись = ел (ральф, 100,менеджер,'/'15<00);
нет
Сравнение разных видов представления базы данных
Наиболее важным различием между описанными выше формами
представления базы данных является то, что для доступа к данным в каж-
каждом случае требуется свой алгоритм. Говоря конкретно, при представлении
базы данных в виде целостных информационных элементов, являющихся
факта>ш, или при представлении атрибутов в виде фактов доступ к (Ъзе
данных должен осуществляться при помощи алгоритма поиска с возвратом
(backtracking algorithm), а при использовании рекурсивных структур дан-
данных (в том числе, списков и двоичных деревьев) доступ должен реаличо-
вываться рекурсивным алгоритмом. Правила и -запросы, приведенные в
настоящем разделе, служат простыми примерами этих алгоритмов. Пред-
Представление в виде двоичного дерева имеет то преимущество, что время по-
поиска конкретной записи будет обычно меньшим, чем при иных представ-
представлениях. Ввиду того, что древовидная структура содержит данные в отсор-
отсортированном виде, при поиске интересующей записи процедуре выборки
понадобится просмотреть меньшее количество записей.
БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ
Трактовка базы данных как потока записей, который может быть
представлен рекурсивной структурой, была предложена в работе [58].
УПРАЖНЕНИЯ
1. Напишите составной запрос, в котором конкретизируется пере-
переменная X, получая значение 10, а затем конкретизируется переменная Y,
которой присваивается значение, получаемое в результате умножения
X на 3.
Напишите заново тот же составной запрос, добавив в него третью
подцель, в которой проверяется, равно ли значение переменной Y числу
300. Как Вы можете объяснить результаты выполнения этих двух запро-
запросов?
2. Напишите правило, позволяющее вычислить площадь прямоуголь-
прямоугольника. У этого правила должны быть три аргумента: основание, высота
и площадь прямоугольника. Напишите несколько запросов к этому пра-
правилу, используя в качестве каждого аргумента и числа, и переменные
|ажнения * 127
, Является ли данная программа обратимой (т.е. являются ли аргумен-
вунаправленными) ?
: 3. Напишите запрос к процедуре "присоединить", в котором два су-
вующих списка объединяются в один - третий список. Запишите
один запрос, генерирующий все возможные комбинации подсписков,
эрые могут быть сформированы из списка, содержащего 10 эле-
тов.
14. Составьте новую версию процедуры "найти слово", в кото-
будет иодсчитываться, сколько раз заданное слово встречается в
tS. Напишите новую версию процедуры "длина", в которой при под-
|е количества элементов списка не учитывается слово "пусто". К при-
\f, для списка
j [a, b, с, d, e]
версия процедуры должна сообщать, что длина списка равна пяти,
% ЩИ списка
Г
}[а, пусто, с, d, пусто]
эцедура должна давать длину, равную трем.
Можно ли переопределить процедуру "можно_путешествовать5"
чтобы она стала симметричной?
'7. Пусть имеется список структур "кл":
[кл (а, 29, 3), кл (Ь, 29, 6), кл (с, 40, 2) ]
Первым аргументом каждой структуры служит имя клиента, вторым — су-
суточный тариф, а третьим — количество дней, на которое взята автомашина.
Напишите правило, позволяющее вычислить итоговую сумму оплаты,
объединяющую выплаты всех клиентов, данные о которых содержатся
в списке.
8. Напишите новую версию процедуры "предок", которая вырабатыва-
вырабатывает список представителей всех промежуточных поколений, располагаю-
располагающихся между предком и потомком. Предположим, например, что Генри
является отцом Джека, Джек — отцом Ричарда, Ричард — отцом Чарльза,
а Чарльз — отцом Джейн. При запросе о том, является ли Генри предком
Джейн, должен выдаваться список, характеризующий родственную связь
Э1их людей, конкретно:
[джек, ричард, чарльз]
9. Напишите новую версию процедуры "можно_путешествовать",
к°торая должна стыковаться с программой "советник по транспорту",
128 ГЛ. 2. АРИФМЕТИКА И СТРУКТУРЫ ДАННЬ!Х
написанной Вами в качестве упражнения к гл. 1. Добавьтее к этой про.
цедуре аргумент, через который будет выдаваться список всех городов
через которые прошел маршрут путешествия от исходного пункта к месту
назначения.
10. Напишите рекурсивную процедуру, которая будет преобразовывать
базу данных, заданную в виде двоичного дерева, в список загписей.
11. Сравните процедуру "нпредок" (см. разд. 1.6) с процедурой
"обр_печать" (см. разд. 2.4). Обе процедуры леворекурсивны. Почему
процедура "обр_печать" работает нормально, а процедура! "нпредок" ра-
ботает некорректно? (Указание: посмотрите, как в заголовках фраз обеих
процедур специфицируются аргументы.)
; глава з
УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
|-
I 3.1. КАК ВЫПОЛНЯЕТСЯ ЗАПРОС В ПРОЛОГЕ
Три семантические модели
В гл. О было сказано, что существуют три различные семантические
юдели, предназначенные для трактовки Пролог-программ: декларатив-
ая модель, процедурная модель и модель в виде абстрактной машины.
I декларативной модели смысл предиката - это определение статического
тношения между термами. Для этой модели порядок следования усло-
ий в правиле не важен. Процедурная модель определяет смысл правила
:ак серию вызовов подпрограмм, что позволяет объяснить действие правил,
которых важно учитывать порядок следования подцелей. Модель в виде
бстрактной машины сходна с бихевиористическими семантическими моде-
йми других языков программирования. В ней специфицируется поведе-
Ие интерпретатора при выполнении конструкций языка Пролог. Эта
годель дает возможность точно описывать побочные эффекты ввода-вы-
рда и управления в Пролог-программах.
Декларативная и процедурная модели были рассмотрены в гл. 1. В дан-
даном разделе рассказывается о работе модели в виде абстрактной машины,
абота этой машины поясняется через операции над стеком активных
апросов. Вначале будет показано, как абстрактная машина выполняет
[ролог-программу, в которой отсутствуют побочные эффекты управле-
ия. Затем рассматривается то, как управляющие конструкции, такие как
ократитъ (cut) и повторить (repeat), влияют на работу абстрактной
шшины.
Выполнение запроса
Работу интерпретатора языка Пролог можно трактовать как рекурсив-
ый циклический процесс унификации (т.е. сопоставления с эталоном)
вычисления подцелей. Действия интерпретатора инициируются запросом.
i ходе выполнения этих действий интерпретатор "опустится" в структуру
екущей программы настолько глубоко, насколько это окажется необ-
одимым для того, чтобы найти факты, требующиеся для определения
стинностного значения запроса. Затем интерпретатор вернется в исходное
остояние, доказав или оказавшись не в состоянии доказать истинность
йпроса.
. Дж. Мал пас
130 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
. После того как пользователь вводит запрос интерпретатору, этот за-
запрос активируется. Интерпретатор приступает к анализу фраз текущей
программы в поисках первой фразы, заголовок которой будет унифици-
унифицироваться с запросом. Для того чтобы запрос унифицировался с заюлов»
ком фразы, нужно совпадение у них имени предикаи и количества аргу-
аргументов и то, чтобы все их аргументы унифицировались. Правила, описываю-
описывающие унификацию термов, приводятся ниже.
Активация согласующейся фразы
После того как фраза, унифицирующаяся с запросом, будет обнаружена,
она активируется. При этом каждая подцель, входящая в тело фразы,
обрабатывается точно так же, как и исходный запрос. Если тело унифи-
унифицирующейся фразы является пустым (т.е. она представляет собой факт),
то запрос сразу же оказывается успешным. Бели ингерпрегаюрне сможет
найти в базе данных фразу, унифицирующуюся с целью, то он возвратит-
возвратится назад. Он возвращается к последней успешной подцели, ликвидирует
конкретизацию любых переменных, явившуюся результатом успешной
обработки этой подцели, и приступает к поиску в множестве фраз теку-
текущей программы заголовка другой фразы, которая унифицируется с дан-
данной подцелью.
Успешное выполнение
При успешном выполнении запроса пользователя интерпретатор вы
водит на терминал значения всех тех переменных, входящих в состав
запроса, которые были конкретизированы в результате процесса обработ-
обработки, или слово да, если переменные в запросе отсутствовали. Если пользе
ватель введет символ ; после того, как интерпретатор нашел ответ, то это
будет эквивалентно отказу от полученного ответа. Интерпретатор вернет-
вернется назади попытается найти иной ответ.
Правила, описывающие унификацию термов
Унификация термов регулируется приводимыми ниже правилами
Во всех примерах используется встроенный предикат =, который выполни
ет попьггку унификации своих аргументов.
1) Переменная унифицируется с константой или структурой. В ре
зультате этого переменная становится конкретизированной, т.е. она при
нимает значение этой константы или структуры.
1 ?- Х-джон.
X = джон
2) Переменная унифицируется с переменной, при этом обе они станс
ll. КАК ВЫПОЛНЯЕТСЯ ЗАПРОС В ПРОЛОГЕ 131
1ятся одной и той же переменной.
! ?-X = Y.
(_1 — это внутреннее имя и неременной X, и переменной Y.)
?) -унифицируется с чем угодно.
! ?— джоан = _.
|) Константа унифицируется с константой, если они идентичны.
! ?— джоан = джоан.
да
) Структура унифицируется с другой структурой, если их имена одинако-
одинаковы, а аргументы поддаются унификации.
| ?-отец(джордж) =отец(Х).
X = джордж
Пример с программой "дядя"
Для того чтобы показать процесс выполнения запроса, воспользуем-
воспользуемся простой программой, состоящей из базы данных "отец", базы данных
"брат" и правила "дядя".
отец(билл, даниэль).
отец (билл, кеннет).
брат (даниэль, кеннет).
брат(джон, билл).
дядя(и,Г>0 :-
брат (U, В),
отец(В,М).
В оставшейся части раздела будем попеременно концентрировать
внимание то на общих действиях интерпретатора, то на конкретных со-
событиях, происходящих при обработке запроса к правилу "дядя".
Активация запроса
После того как пользователь введет запрос, этот запрос помещается
в вершину стека активных запросов. В этом случае говорят, что запрос
активируется. Рассмотрим запрос к программе "дядя":
! ?- дядя (джон. W).
Диаграмма, приводимая ниже, служит "моментальным снимком" состоя-
5*
132 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГР^АММЫ
. , I I !
ния интерпретатора сразу после активации запроси ('дядя(джон, W)".
., , :, • ' ¦ -1' (О
' ' -• Активные запросы — — Фразы программы — . \ '
?-дядя (джон, W).
Как только в стеке появится запрос, интерпретатор приступит к поиску
множества, фраз с тем же самым именем предиката и с тем же количеством
аргументов, что и у запроса. Если таких фраз нет, то запрос оказывается
неудачным. Диаграмма B) показывает запрос, указывающий на начало
множества фраз "дядя":
B)
- Активные запросы - - Фразы программы -
?- дядя(джои, W). -* дядя(и,Г>0 :-
брат (U, В),
oiea(B.N).
Унификация запроса
Интерпретатор анализирует первую фразу множества фраз "дядя"
и пытается унифицировать каждый аргумент запроса с соответствующим
аргументом этой фразы. В нашем случае запрос "дядя" успешно унифици-
унифицируется с заголовком правила "дядя". В результате унификации конкрети-
конкретизируется переменная U, которая получает значение « джон », a W и N стано-
становятся одной и той же неконкретизированной переменной. После того
как переменная, расположенная в заголовке правила, будет унифициро-
унифицирована с другим термом, результат выполнения этих действий распространя-
распространяется на каждый случай использования этой переменной в правиле. Диаграм-,
ма C) показывает состояние интерпретатора сразу после данной унифи-
унификации.
C)
— Активные запросы — — Фразы программы —
?-дядя (джон, W). > дядя (джон, W) :-
брат (джон, В),
отец(В,\У).
Обработка тела фразы
После унификации запроса с заголовком фразы интерпретатор пере-
переходит к телу этой фразы. Если тело фразы пустое (т.е. фраза является
фактом), то запрос сразу же оказывается успешным. Если же тело фразы
не пустое, то интерпретатор помещает в стек запросов каждую подцель,
входящую в тело, и, в свою очередь, обрабатывает ее. Если все подцели
из тела фразы будут успешно обработаны, то и весь исходный запрос будет
успешным.
ОД. КАК ВЫПОЛНЯЕТСЯ ЗАПРОС В ПРОЛОГЕ 133
[-J! Тело правила "дядя" i ( , I
I Тело правила "дядя" образовано со ставным 3anpbeqM « брат(джон. В) »,
;4 отец(В, W)» . Первая подцель - <^ брат(джЪн, В>» - помещается в стек
^апросрв так: »
< '¦ D) A|.
: - Активные запросы - - Фразы программы - ' i
?- дядя(джон,\У)] ; ~-_- ->-*+ дядя(джон, W) : -
'
брат(джон, В),
1 отец(В,\У). . . ,
?- брат(джон. В). * брат(даниэлБ, кеннет).
' '• брат (джон. билл).
Теперь новый запрос - «брат(джон. В)» - является активным запросом.
Исходный запрос - "дядя" - однако все еще находится в стеке в ожида-
ожидании завершения обработки тела правила "дядя". Запрос "брат" теперь
указывает на начало множества фраз "брат".
Если попытка унификации будет неудачной,
то переход к следующей фразе
Если попытка унификации запроса с заголовком фразы закончится
неудачей, то интерпретатор перейдет к анализу следующей фразы соот-
соответствующего множества. Этот процесс будет продолжаться до тех пор,
пока не обнаружится фраза, которую можно будет унифицировать с за-
запросом. Если интерпретатор достигнет конца множества фраз, не обнару-
обнаружив фразу, поддающуюся унификации, то запрос завершится неудачей.
Обработка подцели "брат"
Интерпретатор предпринимает попытку унифицировать подцель
«брат(джон, В)» с фразой « брат(даниэль, кеннет)». Эта попытка за-
заканчивается неудачей, так как « джон » не унифицируется с «даниэль».
Затем интерпретатор переходит к анализу следующей фразы "брат":
E)
— Активные запросы — — Фразы программы—
?- дядя(джон, W). > дядя(джон, W) : -
брат (джон, В),
отец(В,\У).
брат (даниэль, кеннет).
?- брат(джон, В). > брат(джон, билл).
Запрос «брат(джон. В) » унифицируется с фразой «брат(джон, билл)»,
в результате чего конкретизируется переменная В. Эта переменная полу-
получает значение «билл». После выполнения данной унификации состояние
134
ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
интерпретатора cxanei таким:
— Активные запросы —
?- дядя (джон, W).
F)
- Фразы программы - ?'
дядя (джон, W) : -
брат(джон, билл),
отец(билл, W).
брат(даниэль. кеннет).
?- брат(джон, билл). • > брат(джон, билл).
В результате последней унификации переменная В получает значение
«билл». Это значение будет использоваться при каждом употреблении
переменной В в правиле "дядя".
Подцсгь "брат" дает положительный результат
Фраза «брат(джон, билл)» является фактом (у нее пустое тело)
поэтому подцель "брат" сразу же оказывается успешной. Теперь интер-
интерпретатор помещает в вершину стека вторую подцель правила "дядя":
«отец(билл,\У)».
G)
— Активные запросы —
'.'- дядя (джон, W).
?- брат (джон, билл).
?- отец(билл,\У).
— Фразы программы —
дядя (джон, W) : -
брат (джон, билл),
отец(бшш, W).
брат(даниэль, кеннет).
брат (джон, билл).
отец (билл, даниэль).
отец (билл, кеннет).
Обработка подцели "отец"
Интерпретатор пытается унифицировать подцель «отец (билл, W)» с
фразой <(отец(билл, даниэль)». Эта попытка приводит к успеху, в резуль-
результате чего конкретизируется переменная W. Она получает значение
«даниэль». Теперь состояние интерпретатора таково:
(8)
— Фразы программы —
* дядя (джон, даниэль) : -
брат (джон, билл),
отец(билл, даниэль).
брат (даниэль, кеннет).
— Активные запросы —
?- дядя (джон, даниэль).
?— брат (джон, билл).
?— отец(билл, даниэль).
брат (джон, билл).
отец (билл, даниэль).
отец (билл, кеннет).
13.1. КАК ВЫПОЛНЯЕТСЯ о ' 1 (РОС В 1ГОЛОГЕ 135
Фраза « отец(билл,даниэль)» чвляется фактом, поэтому запрос "отец"
сразу же оказывается >снгинь... Больше подцелей в теле правила "дядя"
нег, следовательно, и исходный запрос "дядя" будет успешным. Интер-
Интерпретатор выводит значение переменной W: ~
W = даниэдь
Обратите внимание на то, что после отыскания первого ответа весь стек
активных запросов сохраняется.
Неудача запроса и возврат назад
Если активный запрос достигнет конца соответствующего множества
• раз, то он завершится неудачей. Если такой активный запрос служит
:тью составного запроса (т.е. списка подцелей) и не является первой
подцелью этого составного запроса, то интерпретатор возвратится назад,
чюбы повторно проанализировать предыдущую подцель составного за-
запроса. Если же активный запрос является первой подцельн» и плавного
ыпроса, то неудача активного запроса приводит к неудаче вс-ю состав-
составного запроса. Когда интерпретатор возвращается назад, ликвидируются
нее конкретизации переменных, выполненные последним актива,.: за-
запросом.
Указание интерпретатору вернуться назад — ввод символа ;
После того как интерпретатор найдет один ответ на запрос, пользова-
пользователь может попросить найти еще один ответ. Для этого вводится сим-
символ ; , который означает отказ от только что полученного ответа. Это
заставляет интерпретатор возвратиться назад и приступить к поиску друго-
другого ответа. Точнее говоря, ввод символа ; приводит к неудаче запроса,
активированного самым последним (т.е. запроса, расположенного в вер-
вершине стека). Это происходит уже после получения позитивного ответа
на запрос. Интерпретатор покидает текущее положение в множестве соот-
соответствующих фраз. Если неременные были конкретизированы при по-
последнем успешном выполнении данного запроса, то результаты конкрети-
конкретизации теряют свою силу. Интерпретатор приступает к повторной обработ-
:е этого запроса, начиная со следующей доступной фразы.
Другой ответ на запрос "дядя "
Предположим, что после получения первого ответа {(W = даниэлъ)) на
(апрос "дядя" пользователь вводит символ ;. Подцель "отец", стоящая
\ вершине стека, принудительно делается неудачной, а конкретизация
йеременной W, осуществленная при последнем успехе этой цели, теряет
Свою силу. Интерпретатор переходит к попытке унифицировать данную
136 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
подцель со следующей доступной фразой "отец":
(9)
— Активные запросы —
?- дядя(джон,\\0.
?- брат(джон, билл).
?-отец(билл, W).
— Фразы программы —
дядя(джои, W) : -
брат (джон, билл),
отец(билл, W).
брат(даниэль, кеннет).
брат(пжон, билл).
отец(билл, даниэль).
отеи(билл, кеннет).
Интерпретатор унифицирует подцель «отец(билл, W)» с фразой <(отец(билл,
кеннет)». В результате этого выполняется конкретизация переменной W,
которая получает значение «кеннет». Теперь состояние интерпретатора
таково:
— Активные запросы —
?- дядя (джон, кеннет).
?- брат (джон, билл).
?- отец (билл, кеннет).
(Ю)
~ Фразы программы —
дядя (джон, кеннет) : -
брат (джон, билл),
отец(билл, кеннет).
брат(даниэль, кениет).
брат (джон, билл).
отец (билл, даниэль).
отец (билл, кеннет).
Здесь запрос "дядя" опять оказывается успешным. Интерпретатор выве-
выведет новое значение переменной W:
W= кеннет
Поиск третьего ответа
Предположим, что пользователь ввел еще раз символ ;, отказываясь
тем самым от последнего решения. Это заставит интерпретатор приступить
к поиску еще одного ответа. Такое действие пользователя приведет к
неудаче подцели "отец", конкретизация переменной W, имевшей значе-
значение «кеннет», ликвидируется. Но теперь уже подцель "отец" достигла
1. КАК ВЫПОЛНЯЕТСЯ ЗАПРОС В ПРОЛОГЕ
137
:онца множества фраз "отец":
— Акгивные запросы —
9~ ДЯДЯ (ДЖОН, W).
?- брат (джон, билл).
A1)
— Фразы программы —
дядя (джон, W) : -
брат (джон, билл),
отец (билл, W).
брат(даниэль, кеннет).
брат (джон, билл).
отец (билл, даниэль).
отец(билл, кеннет).
9- отец (билл. W) .
этом месте запрос "отец" терпит неудачу и удаляется из стека. Затем
(терпретатор возвращается назад к предыдущей подцели составного за-
юса, т.е. к «брат(джон, В)». Возврат вызывает замену последнего успе-
л подцели "брат" на неудачу, при этом конкретизация переменной В теря-
t свою силу. Однако же теперь запрос "брат" достиг конца множества
фаз "брат":
(И)
- Активные запросы
?- дядя(джон, W).
?— брат (джон, В).
— Фразы программы —
дядя(джон, W) : -
брат (джон, В),
отец(В,\У).
брат (даниэль, кеннет).
брат (джон, билл).
оэтому подцель "брат" терпит неудачу и удаляется из стека. Поскольку
la являлась первой подцелью в теле правила "дядя", то и все правило
1ядя" тгрпит неудачу1. Интерпретатор возвращается назад и ищет другую
разу "дядя". Но'в э-ом месте запрос "дядя" уже достиг конца множества
з "дядя":
A3)
- Активные запросы - - Фразы программы -
дядя (джон, W) : -
брат (джон, В),
отец(В, W).
•?-дядя(джон, W). *
8 итоге получается, что запрос "дядя" терпит неудачу и удаляется из стека.
138
ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Интерпретатор выдает ответ:
нет
Это означает, что он больше не может отыскать позитивною огвета на за-
запрос. Далее интерпретатор возвращается к сообщению-подсказке верхне-
верхнего уровня.
Поиск несуществующих ответов
Продемонстрируем на более сложном примере то, как интерпретатор
иногда теряет время впустую на поиски несуществующих ответов. Пра-
Правило "'регистрация", приводимое ниже, специфицирует, какие лица долж-
должны -зарегистрироваться для прохождения обязательной воинской службы.
возраст(брайен, 18),
возраст(майк, 17). _ " .
возраст(стив, 18). ¦ -
мужчина (брайен).
мужчина (майк).
мужчина (став).
регистрация(Х) : —
мужчина (X), возраст(Х, Y), Y - 18.
Выполнение запроса к правилу "регистрация"
Предположим, что пользователь ввел запрос:
] ?- регистрация (W).
Диаграммы, приводимые далее, иллюстрируют шаги, которые будет вы>
полнять интерпретатор при обработе данного запроса.
О)
— Активные запросы —
?•- регистрация (W)
- Активные запреем
?- регастрацияО?).
?— мужчина (W).
-¦ Фразы программы —
B)
мужчина (W), возраст (W, Y),
Y--18.
— Фразы программы —
регистрация(W) :- ¦
мужчина(W), возраст(W, У),
Y-18.
мужчина (брайен).
мужчина (майк).
мужчина (стив).
Ll. КАК ВЫПОЛНЯЕТСЯ ЗАПРОС В ПРОЛОГЕ 139
C)
- Активные запросы - - Фразы программы -
?- регистрация (брайен). > регистрация (брайен) :—
мужчина (брайен),
возраст (брайен, Y), Y = 18.
?-мужчина (брайен). *¦ мужчина (брайен).
мужчина (майк).
мужчина (стив).
?- возраст (брайен, Y). >¦ возраст (брайен, 18).
возраст(майк, 17).
возраст(стив, 18).
D)
- Активные запросы -
?- pei истрация(брайен) .
?- мужчина (брайен).
?— возраст (брайен, 18).
?- 18=18
— Фразы программы —
регистрация (брайен) :-
мужчина (брайен),
возраст(брайен,18),
18 = 18.
мужчина (брайен).
мужчина (майк).
мужчина (стив).
возраст(брайен, 18).
;юзраст(майк, 17).
возраст (стив. 18).
этом месте запрос оказывается успешным, и интерпретгг.ш выводит:
W- брайен
Другой ответ
Но посмотрим, что произойдет, гели пользователь введет символ
Юрашивая иной ответ:
(S)
— Активные запросы - — Фразы программы —
?- регистрация(брайен). * регистрация(брайен) ;-
мужчина (брайен).
возраст(брайен. Y),
Y=18.
?— мужчина (брайен).
мужчина (брайен).
мужчина (майк).
мужчина (стив).
140
ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММ^!
?- возраст (брайен, Y).
— Активные запросы —
?— регистрация (брайен).
?- мужчина (брайен)
F)
возраст (брайен, 18). /
возраст(майк, 17).
возраст(стив, 18). |
— Фразы программы — \
регистрация (брайен) :-
мужчина (брайен),
возраст (брайен, Y),
Y=18.
мужчина (брайен).
мужчина (майк).
мужчина (став).
возраст (брайен, 18).
возраст (майк, П}.
?-возраст (брайен, Y) > возраст(стив, 18); ¦
— Активные запросы — — Фразы программы —
?-регистрация (брайен). > регистрация{брайен) :—
мужчина (брайен),
возраст (брайен, Y),
Y=18.
?—мужчина ^брайен) > мужчина (брайен).
мужчина (майк).
мужчина (стив).
возраст(брайен, 18).
возраст(майк, 17).
возраст(стив, 18).
?—возраст (брайен, Y). >
(8)
- Активные запросы - - Фразы программы -
?-регистрация(W), > регистрация (W) :- f
мужчина(\У),
возраст (W,Y),Y= 18. '
мужчина (брайен).
?-мужчина(\У). »• мужчина (майк).
мужчина (стив). ¦
Теперь при конкретизации переменной W значением «майк» запрос потер-
потерпит неудачу, так как Майку лишь 17 лет. Однако запрос будет вновь успеш-
успешным, когда переменная W получит при конкретизации значение «стив».
.'2. ПРЕДИКАТ "СОКРАТИТЬ" 141
Бесполезный поиск другого возраста
Заметьте, как много времени тратит интерпретатор впустую в поисках
ie одного возраста Брайена. Интуитивно мы понимаем, что взаимосвязь
:жду лицом и его возрастом - это отношение вида многие-к-одному,
поэтому мы и не предполагаем найти второе значение возраста для Брайе-
Брайена. Однако интерпретатор языка Пролог чисто механически просматрива-
просматривает всю оставшуюся часть базы данных "возраст" уже после того, как воз-
возраст Брайена был определен. Если база данных "возраст" будет иметь
большой объем, то этот поиск может занять значительное время. В сле-
следующем разделе рассказывается о том, как при помощи встроенного
предиката "сократить" можно избавиться от такого рода бесполезного
поиска.
Автоматический просмотр выполнения программы
Во всех версиях языка Пролог имеются отладочные средства, пре-
предоставляющие возможность пользователю наблюдать за работой интер-
интерпретатора при выполнении запроса. Эти средства будут различными в
разных версиях языка. Поэтому для того, чтобы выяснить, какие отладоч-
отладочные средства есть в Вашей версии Пролога и как этими средствами пользо-
пользоваться, следует обратиться к руководству по Вашей версии Пролога или
к приложению IV данной книги. Если отладочные средства Вашей версии
Пролога слишком слабы, то можно воспользоваться программой из гл. 7,
которая называется "вид" (сокращение от "видимый Пролог"). Эта
программа обеспечивает выдачу весьма подробной отладочной информа-
информации. Итак, если Вам необходимо точно знать, что делает интерпретатор
при выполнении запроса (т.е. если требуется узнать, где он начинает де-
делать не то, что хочет программист, или узнать, не тратит ли интерпретатор
Время впустую), то можно:
1) построить подробные диаграммы активных запросов (аналогичные
Диаграммам из данной главы), которые описывают действия, предприни-
предпринимаемые интерпретатором;
2) воспользоваться отладочными средствами Вашего интерпретатора
Для наблюдения за ходом выполнения программы; или
3) ввести программу "вид" из разд. 7.3 и использовать ее для наблюде-
наблюдения за ходом выполнения программы.
[• 3.2. ПРЕДИКАТ "СОКРАТИТЬ"
Пространство поиска запроса
Пространство поиска запроса - это множество всех возможных от-
етов, рассматриваемых интерпретатором при выполнении запроса. В пре-
Мдущем разделе были полностью исследованы пространства поиска за-
росов к правилам "дядя" и "регистрация". Ясно, что часть пространства
142 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
/
поиска запроса "регистрация" когда интерпретатор пытается найти
второй возраст Брайена - не влияет на способность программы находить
правильные ответы. Эту часть пространства поиска можно отбросить с
целью повышения эффективности работы программы. /
Прс.шкаг "сократить" останавливает возврат назад i!''
Cyi!U4iH'ii специальный встроенный предикат "сократить" (записы-
(записывается как символ !), который дает указание интерпретатору не возвра-
возвращаться назад далее той точки, где стоит этот предикат. Предикат "сокра-
"сократить" применяется главным образом для уменьшения размера пространст-
пространства поиска запроса. Этим предикатом, однако, следует пользоваться с осто-
осторожностью. Он не имеет четкого декларативного смысла (т.е. он всегда
будет истинным), поэтому при употреблении данного предиката будет
наноситься некоторый ущерб понятности программы. Наличие предиката
"сократить" может непредвиденным образом нарушить работу программы.
Предикат "сократить"' по-разному действует на составной, запрос
и на множество фраз, образующих процедуру. Эти два вида действия пре-
предиката четко различаются между собой.
Влияние предиката "сократить" на составной запрос
Рассмотрим случай, когда предикат "сократить" является одной из
подцелей составного запроса. После того как интерпретатор пройдет пре-
предикат "сократить", он больше не сможет возвратиться назад к подцелям,
стоящим перед этим предикатом. Таким образом, предикат "сократить"
действует так, что интерпретатор обязан использовать те значения пере-
переменных, расположенных слева от предиката, которые они получили при
конкретизации.
Пример составного запооса с предикатом "сократить":
: ?- а(Х), b(Y), !. с(Х. Y. Z).
При выполнении данного запроса интерпретатор пройдет через предикат
"сократить" только в том случае, если и подцель а(Х), и подцель b(Y)
окажутся успешными. После того как предикат "сократить" будет обрабо-
обработан, интерпретатор не сможет возвратиться назад для повторного рассмотре-
рассмотрения подцелей "а" и "Ь'\ если подцель "с" потерпит неудачу при текущих
значениях переменных X и Y.
Этот составной запрос не обладает декларативным смыслом. При про-
процедурном подходе, однако, его можно прочесть так:
Взять значение переменной X из подцели "а"
и значение переменной Y из подцели "Ь ", :п
а затем выполнить подцель с(Х, Y, Z). '
L.2. ПРЕДИКАТ "СОКРАТИТЬ"
143
\ , Влияние предикага "сократить" на процедуру
i
\ Предположим, что интерпретатор возвращается назад через множест-
о фраз, образующих процедуру. В теле одной из фраз находится преди-
предикат "сократить". Если интерпретатор дойдет до этого предиката, то он не
сможет вернуться далее назад для рассмотрения остальных фраз данного
множества.
Процедура "а", в которой не используется предикат "сократить"
Рассмотрим в качестве примера два варианта процедуры "а" - с ис-
тыюванием и без использования предиката "сократить". Если этот пре-
<ат не употребляется, то процедура "а" определяется следующим
|кбразом:
write ('один').
а(Х) :-
d(X),
write ('два').
I- аC) :-
write('Tpn').
d('2b').
snpoc к процедуре "а" даст такие ответы:
I '! a(N).
один
два
два
три
N=3 ;
нет
144 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
В точке выдачи второго ответа состояние интерпретатора будет таким:
- Активные запросы — — Фразы программы — /
()
write ('один').
?-а('2а'). -^ * а('2а'):~
d('2a'),
write('flBa').
аC) :-¦
'
?-d('2a'). > d('2a').
d('2b').
Процедура "al", в которой используется предикат "сократить "
В другой версии процедуры "а", названной "аГ'.в середине второго
правила расположен предикат "сократить": . -
al(X) :-
d(X),
! , % сократить
write('flea').
alC) :-
write('TpH').
d('2a').
d('2b').
Посмотрим, что получится, если интерпретатор будет обрабатьгаать такой
запрос к процедуре "al":
1 ?-al(N).
один
N=1 ;
Если пользователь введет символ ; , то интерпретатор возвратится назад
и начнет обрабатывать тело второго правила процедуры "al". Подцель
"d" конкретизирует переменную X значением 2а, интерпретатор прохо-
проходит предикат "сократить", а затем подцель "write" выводит слово « два »
на экран дисплея:
два
N = 2a ;
Поведение интерпретатора при выдаче первых двух ответов, показан-
показанных выше, является точно таким же, как и при выдаче ответов на запрос
i . 1РЕДИКАТ "СОКРАТИТЬ" 145
< ;юцедуре "а". Действие предиката "сократить" пока еще не прояви-
юсь. Но посмотрим, что получится, если пользователь захочет получить
Третий ответ. Интерпретатор попытается возвратиться назад от подцели
[(write ('два')». Однако из-за влияния предиката "сократить" на состав-
ой запрос интерпретатор не может вернуться обратно к подцели "d(X)"
р получения нового значения переменной X. А вследствие действия пре-
иката "сократить" на множество фраз программы интерпретатор не будет
ассматривать третье правило процедуры "al". Поэтому больше не бу-
бурт получено позитивных ответов, и интерпретатор выдаст сообщение:
нет
Итак, из-за действия предиката "сократить" состояние интерпретато-
а после второго ответа будет таким:
- Активные запросы - - Фразы программы -
al(l):-
write('on«H').
al(X) :-
d(X),
alC) :-
write('Tpn').
>
d('2a').
d('2b').
>
Предикат "сократить" как подцель в составном запросе
Приведем несколько примеров, иллюстрирующих применение предика-
предиката "сократить". Если предикат "сократить" будет последней подцелью
составного запроса, то это будет гарантировать получение только одного
ответа на данный запрос:
| ?-дядя (джон, W), !.
W= даниэль ;
нет
Использование предиката "сократить" для того,
чтобы сделать процедуру детерминированной
Детерминированной называется такая процедура, про которую интерпре-
интерпретатору известно, что она дает более одного (позитивного) ответа. Для то-
того чтобы превратить процедуру в детерминированную, в большинстве слу-
случаев можно воспользоваться предикатом "сократить", К примеру, если
мы
146 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАМ;
/
в конце каждого правила рекурсивной процедуры, выполняющей обработ-
обработку списков, поставить предикат "сократить", то это позволит избежать по-
потерь времени, затрачиваемого впустую на поиск дополнительных ответов
поете достижения конца списка. Предикат "сократить" информирует ин-
интерпретатор о том, что процедура является детерминированной. Приведем
текст детерминированной версии процедуры "элемент", которая получила
название "элемент_тест":
элемент _ тест (X, [XI Остаток]) :-¦ !.
элемент _ тест (X, [Y! Остаток]) : —
! .элемент тест (X, Остаток).
| ? -элемент _ тест (с, [а, Ь, с, dj).
да .
Однако применение предиката "сократить" приводит к тому, что данная
процедура не может выдать все элементы списка:
; ?- элемент_тест (X, [а, Ь, с, d] ).
Х = а ;
нет
Применение предиката "сократить"
для отбрасывания части пространства поиска
При рассмотрении программы "регистрация", представленной ранее,
было обнаружено, что интерпретатор тратит понапрасну время в попытке
найтн более чем одно значение возраста у одного и того же лица. Сущест-
Существуют два подхода к этой проблеме. Во-первых, ясно, что часть пространст-
пространства поиска запроса к программе "регистрация" не несет полезной инфор-
информации. Эту часть пространства можно отбросить без какого-либо ущерба
для способности программы выдавать все правильные ответы. Во-вторых,
нужно сделать так, чтобы отношение "возраст" регулировалось oipami-
чением, обеспечивающим целостность отношения, вида многие-к-одному,
а не принимаемым по умолчанию ограничением многие-к-многим. Возни-
Возникает вопрос: как можно использовать предикат "сократить" при созда-
создании повой версии процедуры "регистрация", в которой выдавались бы все
те же ответы, что и в исходной версии, а бесполезные траты времени на
поиск нескольких значений возраста были бы устранены? В связи с этим
возникает и другой вопрос: каким образом можно употребить преди-
предикат "сократить" для того, чтобы создать версию отношения "возраст",
регулируемую ограничением, обеспечивающим целостность, вида многие-
к-одному?
|а.\ ПРЕДИКАТ "СОКРАТИТЬ" 147
fl
! Остановка после выдачи одного ответа
Начнем с более простой задачи — написать запрос к базе данных "воз-
"возраст", при котором будет выдаваться только один ответ. К какому реше-
решению мы бы ни пришли, оно может оказаться полезным при составлении
будущей версии процедуры "регистрация".
Наиболее очевидным способом составления запроса к базе данных
"возраст", при котором будет выдаваться только один ответ, будет напи-
написание составного запроса, второй подцелью которого является предикат
"сократить". Если первым аргументом предик^а "возраст" будет констан-
константа (имя), а вторым — переменная (возраст), то запрос будет работать
нормально:
1,озраст(брайен, 18).
возраст (майк, 17).
возраст (стив, 18).
\ ?- возраст(брайен, Y), ! .
Y=18 ;
нет
Заметьте, что при данном запросе интерпретатор не будет искать значение
еще одного возраста Брайена.
Однако, если первым аргументом запроса "возраст" будет переменная,
а вторым — константа, то при описанном подходе интерпретатор не найдет
все правильные ответы на запрос:
; ?-возраст(X, 18), ! .
X = брайен ;
нет
В базе данных содержатся сведения более чем об одном восемнадцатилет-
восемнадцатилетнем мужчине, но из-за употребления предиката "сократить" этот запрос
выдаст сведения только о первом из представленных мужчин. Поэтому
множество ответов данной программы будет неполным.
Предикат "сократить"как подцель правила "регистрация"
Посмотрим, что получится, если составной запрос подобного вида
(т.е. подцель "возраст" плюс предикат "сократить") будет записан в теле
правила "регистрация".
регистрация2 (X) : -
мужчина (X), возраст (X, Y), ! , Y= 18.
Запрос к правилу "регистрация2" будет работать правильно, если его ар-
148 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
гументом является константа:
1 ?- регистрация2 (брайеи).
да
\ ?- регистрация2 (майк).
нет
Дело будет обстоять не так хорошо, если аргументом запроса является пе-
переменная:
! ? - регистрация2 (X).
Х= брайен ;
нет
Этот запрос не выдает еще один ответ, « X = став », поэтому опять множест-
множество ответов программы будет неполным.
Ограничение сферы действия предиката "сократить"
Необходимо найти способ ограничить сферу действия предиката "сокра-
"сократить ". Мы хотим сохранить влияние этого предиката на подцель "возраст",
устранив одновременно действие данного предиката на составной запрос,
образующий тело правила "регистрация". Этого можно добиться, если пере-
перенести предикат "сократить" из правила "регистрация" на более низкий уро-
уровень, каким и является сама база данных "возраст". Построим базу данных
"хвозраст", в которой каждая фраза является правилом с единственной
подцелью — предикатом "сократить".
хвозраст(брайен, 18) :— ! .
хвозраст (майк, 17) :— ! .
хвозраст (стив, 18) :- !.
регистрацияЗ (X) : -
мужчина(X), хвозраст (X, Y), Y = =18.
Запрос к программе "регистрацияЗ" теперь будет выполняться корректно и
в случае, когда аргументом служит константа, и тогда, когда аргументом
является переменная:
] ?—регистрацияЗ (майк).
нет
\ ?-регистрацияЗ (X).
X= брайен ;
Х-стив ;
нет
Поскольку в каждое правило "хвозраст" входит предикат "сократить",
интерпретатор не будет пытаться найти у кого-нибудь более чем один воз-
.2. ПРЕДИКАТ "СОКРАТИТЬ" 149
>аст. Тем самым отбрасывается бесполезная часть пространства поиска,
ну не оказывает никакого влияния на полноту множества ответов. В соот-
1етствии с приведенным выше запросом были найдены и Брайен, и Стив.
Однако решив проблему для правила "регистрация", мы создали новые
рудности для правил "хвозраст". Простой запрос к "хвозраст" с аргу-
(ентами-переменными не позволяет получить из базы данных все сведения
1б именах и возрасте людей:
I ?- хвозраст (X, Y).
1 X = брайен
Y = 18 ;
| нет
рвершенно очевидно, что множество ответов является неполным. В базе
Энных есть и другие ответы, но интерпретатор не найдет их из-за действия
[редиката "сократить". Такой способ использования предикатов "сокра-
ить" приводит к ухудшению модульности программы — в том смысле,
>го на любое правило или составной запрос, в которых предпринимается
юпытка применения правил "хвозраст" в качестве подцели, будут также
лиять и предикаты "сократить", расположенные в теле правил "хвоз-
цст". В идеале программист не должен был бы думать о том, как предикат
'сократить", расположенный в подпроцедуре, будет влиять на вызываю-
вызывающую ее процедуру.
\ Общее правило ограничения сферы действия предиката "сократить"
' При более гибком подходе к этой проблеме следует оставить базу
[Внных "возраст" в ее исходном виде, т.е. без предикатов "сократить",
; написать специальное правило, задача которого заключается только
йшь в ограничении сферы действия предиката "сократить". Аргументом
акого правила, названного "один_раз", является запрос. Тело этого
;равила состоит из двух подцелей — из запроса и предиката "сократить".
[ри выполнении правила "один_раз" этот предикат гарантирует, что бу-
бурт найден только один ответ на запрос. Если правило "один раз" вой-
|вт в составной запрос, то интерпретатор сможет возвратиться назад через
Ifcro, т.е. это правило не оказывает на составной запрос такого действия,
Ык предикат "сократить". Приведем определение правила "один_раз"
\ версию процедуры "регистрация", в которой это правило используется:
' одинраз(Р) :-
| ' ~Р' ! ¦
I регистрация4 (X) : —
j мужчина(Х), один_ раз (возраст (X, Y)), Y = =18.
| 1 ?—регистрация4 (брайен).
i да
150 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
I ?- регистрация4(Х).
X - брайен ;
X = стив ;
нет
Если Вам непонятно такое использование правила "одинраз", то вспом-
вспомните, что аргументом предиката может быть структура. В запросе к пра
вилу "один_раз" структурой является «возраст(Х, Y)». Эта структура
преобразуется внутри правила "один раз" в подцель.
Программа "регистрация4" удовлетворяет нашим требованиям во всех
отношениях. Поскольку в правило "один_ psi" включен предикат "сокра-
"сократить", интерпретатор не будет понапрасну трашгь время на поиски сще од-
одного возраста для одного и того же человека. База данных "возраст" не
содержит предикатов "сократить", и поэтому ее можно использовать не
только в программе "регистрация-*", но и'для других целей (т.е. сохраняет-
сохраняется модульность). В тело правила "регистрация-*" предикат "сократить"
напрямую не входит, поэтому множество ответов на запрос к программе
"регистрация-*" будет полным. fi
3.3. ОТРИЦАНИЕ КАК НЕУДАЧА ЗАПРОСА
Негативная информация
Информация о фактах, которые не являются истинными, или об отно
шениях, которые не соблюдаются, называется негативной. Обычно негатив
ная информация не хранится в Пролог-программах в явной форме. Вместо
этого считается, что вся информация, отсутствующая в текущем множестве
фраз, ложна. Это эквивалентно предположению о том, что всегда имеет
силу следующее правило:
Если фраза Р не представлена в текущей программе, то считается,
что представлено отрицание Р.
Предположение о замкнутости мира
С практической точки зрения это означает, что интерпретатор не можс i
отличить неизвестную фразу от доказуемо неистинной фразы. Правило,
приведенное выше, известно как предположение о замкнутости мира
Множество фраз текущей программы называется миром. Это — замкну
тый мир, поскольку интерпретатор ведет себя так, как будто бы в этом
мире содержатся все возможные знания. Предположение о замкнутости
мира является результатом действия неявного предиката метаязыка
описывающего смысл запроса в языке Пролог (см. разд. 0.9) .
'¦'отрицание как неудача запроса
151
Тогда и только тогда, когда
Вследствие того, что предполагается замкнутость мира, множество
|з, определяющих отношение, имеет металингвистический смысл, не-
шько опирающийся oi ею смысла с позиций объектного языка.. Пред-
зжи>!. к примеру, что в программе представлены три фразы "началь-
начальник (Джордж).
начальник (гарри).
начальник (юней)
i уровне объектного ятыка смысл этих фраз следующий:
X является начальником, ееш
X - это « Джордж » или
X — эго « Гарри » или
Х-это «Нэнси».
нако из-эа предположения о замкнутости мира фактический смысл
|х трех фраз на уровне метаязыка бупят даскопмсо иным:
X является начшшшком тггда и только гогцй. когда
X -¦то«Н ».
:н "точько топ' .оявлле!ся вследствие предположения о замкнутос-
ра.
Предположение об открытости мира
При работе с неизвестной информацией альтернативой предположению
Цвмкнутости мира служит предположение об открытости мира:
Если фраза Р отсутствует в текущей программе, то считается, что Р
ни истина, ни ложна.
^ответствии с предположением об открытости мира запрос может обла-
одним из трех допустимых истинностных значений: истина, ложь
неизвестно. Если запрос признан неизвестным, то программа может
ринять какие-то особые действия, скажем, она может обратиться
1ьтернативному источнику знаний. По умолчанию интерпретатор языка
inor руководствуется предположением о замкнутости мира. Поэтому
требуется, чтобы поведение программы соответствовало предположе-
об открытости мира, то это нужно выражать в явном виде при состав-
программы. Составление такой программы равнозначно изменению
ного предиката метаязыка, описывающего с\"ысл запроса.
ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Отрицание в явной форме
Встроенный предикат "not" ("не"), который в некоторых версиях
языка Пролог записывается как "\ + '\ имеет один аргумент. Этим аргу-
аргументом является запрос значение истинности которого (после обработки
данного запроса) заменяется ьа противоположное. Если запрос успешен,
то отрицание этого запроса является неудачей и, наоборот, «ели запрос
терпит неудачу, то его отрицание будет успехом. Запрос:
I ?-1кП(отец(питер,Х)). , % A)
будет истинным тогда и только тогда, когда
; ?- отец (питер, X). % B)
потерпит неудачу.
Квантификация переменных в запросе с предикатом "not"
Как отмечалось в разд. 1.3, переменная X в запросе B), приведенном
выше, квантифицирована экзистенциально. Запрос B) соответствует
вопросу:
Существует ли некоторый X, для которого Питер является отцом'!
С другой стороны, переменная X в запросе (П квантифицирована универ-
универсально. Запрос A) соответствует вопросу:
Является ли Питер не-отцом ?
(или: Для любого X, является ли Питер не-отцом X?)
Заметьте, что для проверки этого положения требуется отыскание только
одного значения X (означающее кого-либо, кому Питер на самом деле
является отцом), при котором запрос A) потерпит неудачу. Обратите
внимание, что квантификация переменных всегда изменяется на обратную
(т.е. из экзистенциальной превращается в универсальную и наоборот),
если фраза подвергается отрицанию.
Птммер использования предиката "not"
Напишем правило, определяющее сельского жителя как человека,
который не является ни горожанином, ни жителем пригорода.
горожанин (джейк).
житель_пригорода(сюзан).
сельский_житель(Х) : —
not (горожанин (X) ),
not (житель _ пригорода (X) ).
Какой ответ Вы ожидаете получить на запрос:
', ?—сельский_житель(билл).?
3.3. ОТРИЦАНИЕ КАК НЕУДАЧА ЗАПРОСА 253
Пример процедуры, поведение которой
соответствует предположению об открытости мира
Рассмотрим простой пример процедуры, поведение которой соответ-
гвует предположению об открытости мира. Запрос может обладать одним
з трех истинностных значений: истина, ложь или неизвестно. Ложные
гверждения должны быть представлены в текущей программе ь яытам
«де в качестве фактов, имеющих форму «false (X)», где X сам являет-
I фактом. Если нельзя доказать, что утверждение истинно или ложно,
оно считается неизвестным.
доказать (Р) : —
Р, wnte('**HCTHHHo'), nl, ! .
доказать (Р) : -
false(P), \уп1е('**ложно'), nl,! .
доказать (Р) : —
not(P),
not(false(P)),
write('**HeH3BecTHo'), nl.
редположим, что в программу введены факты:
отец (филип, чарльз). % позитивный факт
false (отец(чарльз,Х)). % негативный факт
На примере следующих запросов проиллюстрируем работу процедуры
"доказать":
! ?— доказать (отец (филип, энн)).
**неизвестно
да
I ?— доказать (отец (филип, X)).
**истинно
X = чарльз
Как Вы считаете, какой ответ будет дан на запрос:
I ?— доказать (отец (чарльз, мери)). ?
<54 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ГРОП'АММЫ
3.4. ВСТРОЕННЫЕ ПРЕДИКАТЫ, ^
ПРЕДНАЗНАЧЕННЫЕ ДЛЯ ОБЕСПЕЧЕНИЯ ВВОДА-ВЫВОДА '""
Побочные эффекты ввода-вывода ,
В языке Пролог есть ряд встроенных предикатов, обеспечивающих
ввод и вывод. Каждый из таких предикатов обладает побочным эффектом
ввода-вывода. Это означает, что когда обрабатывается запрос к одному
из предикатов ввода-вывода, то это сказывает некоторое перманентное
воздействие на вычислительную среду, ыкое, скажем, как выв^д сообще-
сообщения на экран терминала или считывание слова из файла.
Каждый предикат ввода-вывода обладает четким процедурным смыс-
смыслом. Однако, как и у предиката "сократить", у данных предикатов отсут-
отсутствует декларативный смысл. Каждый из них является детерминированным
в том смысле, что запрос к такому предикату оудст успешным только
один раз.
put(X) X — целое, значением которою является некото-
некоторый ascii-код. Предикат "put" выводите текущий
выходной поток символ, код которою соответ-
соответствует значению X.
write(X) Предикат "write" выводит терм в текущий выход-
выходной поток.
nl Предикат "nl" записывает в выходной поток при-
признак возврата каретки/перевода строки.
getO(X) Предикат "getO" унифицирует X с ascii-кодом
следующего символа из текущего входного по-
потока.
read(X) Предикат "read" унифицирует X со следующим
термом из текущего входного потока. Ограничи-
Ограничителем терма является точка, за которой следует
пробел или начало новой строки.
Пример:
! ?- read(X).
привет.
Х= привет
Заметьте, что точка, введенная пользователем,
не включается в значение переменной X
Пример запроса, в котором используется предикат "read"
Рассмотрим сложный составной запрос, в котором употребляется пре-
предикат "read". Предположим, что существует база данных с названиями
языков и пользователь, говорящий на французском языке, отвечает и»
1
3.4. ВСТРОЕННЫЕ ПРЕДИКАТЫ ДЛЯ ВВОДА-ВЫВОДА 155
вопросы, которые задает представленный ниже составной запрос.
язык (итальянский).
я шк (немецкий).
язык (японский).
язык (французский).
язык (английский).
I ?- язык(Ь),
write ('Знает* ли Вы '),
write(L), write(' язык ?'), nl,
read(A),
А = да,
write('Ara! Так Вы знаете '),
write(L), write('. язык ! '), nl,
Знаете ли Вы итальянский язык?
нет.
Знаете ли Вы немецкий язык!
нет.
Знаете ли Вы японский язык?
!,нет.
Знаете ли Вы французский язык!
; да.
Ага! Так Вы знаете французский язык!
L = французский
А=да
Алгоритм поиска с возвратом
Составной запрос задает пользователю вопрос о том, знает ли он италь-
итальянский язык, а затем "считывает" ответ пользователя и запоминает его
в переменной А. Если пользователь отвечает нет, то подцель «А = да»
терпит неудачу, и интерпретатор возвращается назад и рассматривает
следующий язык. В конце концов пользователь отвечает да на вопрос о
французском языке, после этого интерпретатор проходит через предикат
"сократить" и печатает некоторые дополнительные сообщения. Предикат
"'сократить" дает гарантию того, что запрос закончится после первого от-
|ета да. Поэтому перед пользователем не был поставлен вопрос о знании
i английского языка.
Данный составной запрос основьшается на алгоритме поиска с возвра-
который получил это название из-за того, что интерпретатор возвра-
возвращается назад при просмотре базы данных "язык". Вначале интерпретатор
Действует циклически. Он перемещается назад и вперед между рассмотре-
рассмотрением нового языка и вопросом пользователю о том, знает ли он этот язык.
156
ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Выход из этого цикла может произойти в двух случаях: 1) когда состав-
составной запрос потерпит неудачу, если в базе данных не останется больше наз-
названий языков, либо 2) когда в процессе выполнения программы будет
пройден предикат "сократить" (запрет возвращения), если пользователь
введет ответ да.
3.5. ВСТРОЕННЫЕ ПРЕДИКАТЫ,
ПРЕДНАЗНАЧЕННЫЕ ДЛЯ УПРАВЛЕНИЯ ФАЙЛАМИ
i В языке Пролог существуют понятия текущего входного потока (из
которого предикаты ввода считывают символы) и текущего выходного
потока (в который предикаты вывода записывают символы). По умол-
умолчанию считаемся, что оба этих потока связаны с пользовательским терми-
терминалом. Приводимые далее предикаты позволяют связывать каждый из
потоков с файлами.
see(F)
seeing(F)
seen
tell(F)
Здесь F — имя файла. Если существует файл с та-
таким именем, допускающий' чтение, то он открыва-
открывается и связьшается с текущим входным потоком.
Любые вызовы предикатов ввода, скажем, преди-
предикатов "read", "getO" и т.д., будут приводить к
считьшанию символов из этого файла.
Этот предикат унифицирует "F" с именем файла,
который ь настоящее время соответствует теку-
текущему входному потоку. Если текущий входной
поток ассоциируется с пользовательским терми-
терминалом, то F унифицируется с константой « user».
Если файл был связан с текущим входным пото-
потоком при помощи предиката "see/1", то предикат
"seen" закрывает зтот файл и опять связывает
с текущим входным потоком пользовательский
терминал. Пример:
! ?-¦ зее('данные'), % открыть входной
% файл
read(R)i, % считать терм |
write(R), % обработать терм
seen. % закрыть файл
Здесь F — имя файла. Этот файл создается или от-
открывается как выходной и связывается с тек> •
щим выходным потоком. Любые вызовы преди-
предикатов вывода, скажем, "write", "put" и т.Д-,
будут приводить к записи символов в этот файл-
( ПРОВЕРКА ТИПА ТЕРМА , 157
telling(F) i Этот предикат конкретизирует F именем файла,
i ¦ ' ' , который в настоящее время соответствует теку-
текущему выходному потоку. Если текущий выход-
выходной поток направлен на пользовательский терми-
терминал, то F конкретизируется значением «user».
told Если файл был связан с текущим выходным по-
потоком при помощи предиката "tell/1", то преди-
предикат "told" закрывает этот файл и опять направ-
направляет текущий выходной поток на пользователь-
пользовательский терминал.
3.6. ПРОВЕРКА ТИПА ТЕРМА
i языке Пролог имеются встроенные предикаты, предназначенные для
ерки типа терма.
\аг(Х) Предикат "var" даст значение истина, если его
аргумент будет неконкретизированиой перемен-
переменной. Пример:
! ?-var(X).
да
\ ?- Х = Лондон, var(X).
нет
В следующем примере "true" — это встроен-
встроенный предикат, который всегда дает истину. Он
часто используется в конструкциях с "или" (сим-
(символ ;).
вывод_по_умолч(Х) : —
(var(X), X = 'внимание: переменная'; true),
write (X), nl.
! ?— вывод_по_умолч(привет).
привет
да
i ?- вывод_по_умолч(Х).
внимание: переменная
да
aonvar(X) Предикат "nonvar" будет истинным, если его ар-
аргументом будет терм любого вида, кроме некон-
кретизированной переменной. Пример:
! ?- X = [париж,лондон,нью_йорк,токио],
nonvar (X).
да
158 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
integer(X) Предикат "integer" даст значение истина, если его
аргументом будет целая константа или перемен-
переменная, конкретизированная целым числом.
atom(X) Предикат "atom" будет истинным, если его аргу-
аргументом служит нецелая константа, например:
; ?- atomA7).
нет
1 ?- аЮт(отец(Х)).
нет
! ?— а1от(париж).
да
Использование предикатов "var" и "nonvar"
Если воспользоваться предикатами 'Var" и "nonvar", то можно соста-
составить процедуру, выполняющую функции интерфейса для базы .данных
"возраст". Эта процедура накладывает ограничение, обеспечивающее це-
целостность отношения, вида многие-к-одному во время выборки информа-
информации.
% Многие Один -—.,
возраст (брайен,18).
возраст (майк, 17).
возраст (став, 18).
% Возраст с ограничением многие-к-одному
мо_возраст (Имя, Возраст) :- % A)
nonvar (Имя),
возраст (Имя, Возраст),!. % сократить
мо_-возраст (Имя, Возраст) : - % B)
var (Имя),
возраст (Имя, Возраст) . % нет "сократить".
Если аргумент "Имя" в запросе к процедуре "мо_возраст" конкретизи-
конкретизирован, то ответ на запрос будет получен по правилу A). Предикат "сок-
"сократить", расположенный в этом правиле после подцели "возраст", обеспе-
обеспечивает устранение бесполезных затрат времени на поиск еще одного зна-
значения возраста после определения первого значения этого параметра. С
другой стороны, если аргумент "Имя" не конкретизирован, то ответ на
запрос будет выдаваться в соответствии с правилом B). В правиле B)
предикат "сократить" отсутствует, поэтому запрос может осуществить
поиск с возвратом по всей базе данных "возраст". Проиллюстрируем эЮ
3V7. ДЕЙСТВИЯ С ТЕКУЩЕЙ ПРОГРАММОЙ 159
примерами.
,' ? — мо _возраст (брайен, X).
X = 18; % ответ по правилу A)
нет
\ ? - мо_возраст (Кто, 18).
Кто - брайен ; % ответы по правилу B)
Кто = стив ;
нет
Теперь можно написать новую версию процедуры "регистрация", кото-
которая получит название "регистрация 5". В ней используется процедура
"мо -возраст". Запрос к процедуре "регистрация 5" всегда будет приво-
приводить к выдаче полного множества ответов без потери времени на бес-
бессмысленный поиск дополнительных значений возраста одного и того же
лица. Применение процедуры "мо_возраст" позволяет сохранить модуль-
модульность и базы данных "возраст", и процедуры "регистрация 5".
регистрация 5 (X) : —
мужчина (X), мо_возраст (X,Y), Y = 18.
' ,' ? - регистрация 5 (X).
X = брайен ;
X = стив
нет
3.7. ДЕЙСТВИЯ С ТЕКУЩЕЙ ПРОГРАММОЙ
Существует ряд встроенных предикатов, позволяющих программными
средствами изменять текущее множество фраз программы.
assert (X) Предикат "assert" ("принять") добавляет к текущей програм-
программе фразу X. Пример:
i ? — assert (король(людовик, франция)).
да
| ? -король (людовик,X).
X = франция
asserta(X) Предикат "asserta" добавляет к текущей программе фразу X
как первую фразу процедуры.
assertz(X) Предикат "assertz" добавляет в текущую программу фразу X
как последнюю фразу процедуры.
160 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
retract(C) Предикат "retract" ("удалить") удаляет из текущей програм-
программы первую фразу, которая унифицируется с С. Предупрежде-
Предупреждение: предикат "retract" является средством деструктивного
присваивания фраз, и пользоваться им следует с осторож-
осторожностью. Пример:
] ? — retract (король(людовик, франция)).
да
j ? — король (людовик, X).
нет
Изменение значения факта '
Напишем короткую программу, в которой употребляются предикаты
"assert" и "ietract" для деструкшвного присваивания значения факта, со-
содержащего текущее время (в часах).
время A0). ' ¦ :•¦¦¦
изменить—время: — ¦ •¦
время (Час), Нов_час is Час + 1, • *}
retract (время (Час)),
assert (время(Нов—час)).
При каждом запросе к процедуре "изменить_время" текущее время увели-
увеличивается на один час:
! ? - изменить_время.
да
! ? - время (X).
Х=П
\ ? - изменигь_время. •
да ,
| ? - время (X).
Алгоритм поиска с возрастом,
в котором используется предикат "assert"
Напишем еще один составной запрос, при помощи которого пользо-
пользователь опрашивается о знании языков. Данный запрос добавляет факты со
сведениями о пользователе в базу данных.
язык (итальянский).
язык (немецкий).
язык (японский).
язык (французский),
язык (английский).
3.7. ДЕЙСТВИЯ С ТЕКУЩЕЙ ПРОГРАММОЙ 161
| ? — write ('Введите Ваше имя: '),
read (Имя),
| язык (Яз),
\ write ('Знаете ли Вы'), write (Яз),
i . write ('язык'),nl,
read (да),
assert (владеет (Имя.Яз)),
fail.
Введите Ваше имя: брайен.
Знаете ли Вы итальянский язык?
нет. 0 ,
Знаете ли Вы немецкий язык?
нет.
Знаете ли Вы японский язык?
да.
Знаете ли Вы французский язык?
нет. .,,,.„ ; ,.,.Г:
Знаете ли Вы английский язык!у-
Л""
нет ¦¦•¦"•¦ ' . . ¦¦ ,vj,:q
! ? - владеет (брайеи, Y). ' "'¦р')ь
Y = японский ;
Y = английский ;
Сначала данный составной запрос спрашивает имя пользователя. Две подце-
подцели, применяющиеся в предыдущей версии программы, — « read (А)» и
«А = да» - теперь объединены в одну — «read (да)» , которая будет истин-
истинной только в том случае, когда пользователь введет слово «да». Если поль-
пользователь признается, что знает определенный язык, то в базу данных добав-
добавляется факт вида «владеет (Имя, Яз)». Встроенный предикат "fail" всегда
приводит к неудаче. Подцель "fail" заставляет интерпретатор возвратиться
назад и взять для рассмотрения новый язык. Этот процесс будет продол-
продолжаться до тех пор, пока не исчерпается перечень языков, после чего весь
составной запрос потерпит неудачу.
В конце описанного выше сеанса работы вводится запрос к базе данных
"владеет", позволяющий отобразить фразы, добавленные в результате вы-
выполнения составного запроса. Несмотря на то, что в конце концов состав-
составной запрос потерпел неудачу, он оказал перманентное воздействие на теку-
текущую программу, осуществив добавление в нее двух фраз "владеет".
Как превратить составной запрос в правило?
6. Дж. Малпас
162 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Процедура, которая учится у пользователя
Предикат "место" связывает название места в городе с номерами улиц
(стрит и авеню), на пересечении которых это место расположено. По задан-
заданному названию места данная процедура попытается определить его адрес,
просматривая базу данных "адрес". Процедура "место" действует в соот-
соответствии с предположением об открытости мира в том смысле, что она не
просто завершается неудачей, если не может найти название места в базе
данных "адрес". Вместо этого процедура переключается на другую страте-
стратегию и получает сведения от пользователя, выступающего в роли альтерна-
альтернативного источника знаний. Процедура "место" учится на своем опыте, до-
добавляя новые ответы в текущую программу.
адрес (уайтхорс, 8,11) .
адрес (урбан_софтвэр, 8, 42).
адрес (милфорд_плаза, 8, 43).
адрес (пенн_стейшн,7,32).
место (X, Авеню, Стрит) : —
адрес (X, Авеню, Стрит),!.
место (X, Авеню, Стрит) : —
nonvar (X), var (Авеню), var (Стрит),
write (' Это место — '), write (X), nl,
write (' вблизи какой авеню? (название + точка)'),
read (Авеню),
write ('вблизи какой стрит? (номер + точка)'),
read (Стрит),
assert (адрес (X, Авеню, Стрит)) .
Нижеследующие запросы иллюстрируют работу процедуры "место":
J ? —место (уайтхорс, Аве, Ст).
Аве = 8
Ст=11
J ?—место (гранд_сентрал, Аве, Ст).
— Это место - гранд _сен трал
вблизи какой авеню? (название + точка) Лексингтон.
вблизи какой стрит? (номер + точка) 42.
Аве = Лексингтон
Ст=42
| ?— место (гранд_сеитрал, Аве, Ст).
Аве = лексингтон
Ст=42
Заметьте, что при выполнении второго запроса система спросила у пользо-
пользователя адрес «гранд—сентрал». Пользователь ввел «лексиигтон» и «42», а
3.7. ДЕЙСТВИЯ С ТЕКУЩЕЙ ПРОГРАММОЙ 163
затем интерпретатор вывел эти же самые значения как ответы на запрос.
Если дать тот же запрос повторно, то процедура "место" уже будет знать
адрес « гранд_сентрал».
Ограничение, обеспечивающее целостность предиката "место"
Какое ограничение, обеспечивающее целостность, будет справедливо
для отношения названия места и его адреса — один-к-одному, один-к-мно-
гим или многие-к-многим ? Какое ограничение, обеспечивающее целост-
целостность, действует неявно для приведенной выше версии правила "место"?
Можете ли Вы составить новую версию процедуры "место", которая
выполняла бы некоторые рациональные действия при таком запросе:
| ?-место (Что, 8,21).
если в базе данных "адрес" нет сведений о каком-либо объекте, распола-
располагающемся иа пересечении 8-й Авеню и 21-й Стрит?
Программа, которая модифицирует сама себя
В качестве последнего примера использования предикатов "assert" и
"retract" рассмотрим программу, которая работает с базой данных, содер-
содержащей сведения о терминалах. При выполнении "изменения" программа за-
запрашивает у пользователя информацию и осуществляет обновление базы
данных.
терминал (vt220, подсоединен).
терминал (tvi 950, подсоединен).
терминал (beehive, подсоединен),
терминал (рс, отсоединен).
терминал (wyse, подсоединен). .
изменить_терминал : —
write ('терминал?' ),
read (Т),
write ('новое состояние?'),
read (С),
retract (терминал (Т, _)),
assert (терминал (Т,С)).
% пример сеанса работы с программой
I ?-терминал (vt220, Состояние).
Состояние = подсоединен
| ?— изменить—терминал.
терминал! vt220.
новое состояние? отсоединен.
да
! ?-терминал (vt220, Состояние).
Состояние = отсоединен
164 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
3.8. КОМПАРАТОРЫ
X = Y Этот предикат унифицирует аргументы. Если оба аргумента
конкретизированы, то предикат проверяет, равны ли они. Ес-
Если один аргумент конкретизирован, а другой — нет, то некон-
кретизированный аргумент получает значение конкретизиро-
конкретизированного. Если аргументами служат неконкретизиро ванные пе-
переменные, то они обе становятся одной и той же переменной.
X - - Y Этот предикат успешен, если его аргументы будут в точности
одинаковы. Он потерпит неудачу с двумя разными некон-
кретизированными переменными. Примеры:
! ?- X = = X. .
да
; ?- х = = y.
нет
\ ?- Х = = альфа.
нет
! ?— альфа = = альфа.
да
X\==Y Этот предикат потерпит неудачу, если оба его аргумента бу-
будут в точности одинаковы- В противном случае предикат
окажется успешным. Примеры:
] ?-альфа \ = = бета.
да
\ ?-Х\== альфа.
да
| ?— альфа \ = = альфа.
нет
3.9. ПРОЧИЕ ВСТРОЕННЫЕ ПРЕДИКАТЫ
S = .. L Предикат " = . ." можно назвать преобразователем *). S -
это терм, a L - список. Данный предикат преобразует
список в терм или наоборот. Если длина списка будет боль-
больше единицы, то этот предикат превратит список в структу-
структуру, причем первый элемент списка станет именем структу-
структуры, а все остальные элементы списка станут аргумента-
аргументами структуры. Примеры:
! ?- отец (джордж, лео) = .. Список.
Список =[отец, джордж, лео]
*) В оригинале — univ. — Примеч. пер.
|?9. ПРОЧИЕ ВСТРОЕННЫЕ ПРЕДИКАТЫ 165
! ?— S = . . [рейс, 450, сан_франциско, лос_анжелес].
5 = рейс D50, сан ^франциско, лос^анжелес)
name(X, L) Здесь X — атом, a L - список кодов символов в соответ-
соответствии с кодовой таблицей ascii. Если X конкретизирована,
! то предикат "name" ("имя") порождает из этого атома
список кодов символов. Если L конкретизирована, то пре-
I дш$ат "name" создает константу из списка кодов L. При-
I меры:
. ] ? — name (help, L).
Г L=flO4,101,108, 112]
\ \ ?-name (X, [ЮЗ, 101, 1П, П4, 103,101]).
I X = george
\ \ ?- name (X, [50,51,52]), integer (X).
\ X" 234
Заметьте, что предикат "name" можно употреблять для
преобразования целого числа или числа с плавающей точ-
точкой в коды символов и наоборот.
Программа ввода "вводполя"
Предикат ввода "read" обладает ограниченными возможностями, пос-
постольку он может считывать только один терм языка Пролог, за которым
следует точка. Встроенный предикат "name" позволяет написать более гиб-
гибкую программу ввода. Программа "вводполя" считывает все символы
вплоть до начала Повой строки. У программы "вводполя" имеется один
аргумент — неконкретизированная переменная, которая будет конкрети-
конкретизирована любым значением, вводимым пользователем. Если первым сим-
символом, который ввел пользователь, является признак перехода к новой
строке (пользователь просто нажал клавишу return), то аргумент прог-
программы "вводполя" останется неконкретизированным.
В программе "вводполя" для ввода списка символов используется
процедура "вводсимв". В процедуре "вводсимв" применена схема счи-
считывания с опережением на один символ. Первым аргументом этой про-
процедуры является предыдущий считанный символ, а возвращает она через
второй аргумент список символов. Если первым аргументом процедуры
будет символ с ascii-кодом 10 (признак перехода к новой строке), то она
возвратит пустой список. В противном случае процедура воспользуется
предикатом "getO" для считьшания еще одного символа. Процесс будет про-
продолжаться рекурсивно, что позволит считать остальные символы строки.
%
вводполя (Поле) : —
getO (С), % если С - признак перехода
166 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
( С =10 % к новой строке, то оста-
% вить неконкретизированной
% переменную Поле.
вводсимв (С, Список), % считать символы вплоть до
% признака перехода к но-
% вой строке
name (Поле, Список) % преобразовать Список в
), !. %атом
% возвратить пустой список, если предыдущим символом является приз-
% нак перехода к новой строке '-р.,
% + - и
вводсимв A0, [ ]):—!¦
вводсимв (С, [С [Остаток]) : —
getO (С 1),вводсимв (С 1,Остаток),!.
[ ?-вводполя (X).
фрэик смит % пользователь вводит значение
X = ' фрэнк смит'
\ ?— вводполя (X).
% пользователь нажимает клавишу return
Х = -1
clause (Н, В) Здесь Н должна быть конкретизирована заголовком фра-
фразы. Предикат "clause" ("фраза") найдет среди фраз текущей прог-
программы такую фразу, заголовок которой унифицируется с Н, и вы-
выполнит унификацию В с телом этой фразы. Если фраза является
фактом, то В будет конкретизирована словом «true». Примеры:
путешествие (амтрак, нью_йорк, бостон, поезд). , ,
можьо_путешествовать (ГородА, ГородВ) : — ' ? '
путешествие (_, ГородА, ГородБ, _),
путешествие (_, ГородБ, ГородВ,_) .
! ?—clause (путешествие(амтрак, Y, Z, поезд), В). \.
Y = нъю_йорк
Z = бостон
В = true
\ ?-clause (можно_путешествовать (X,Y),B).
Х=-0
В = (путешествие{-2, _0, -3, -4), путешествие (_5, _5, -1, -6))
repeat Этот предикат генерирует бесконечное число циклов повторе-
повторения поиска с возвратом. Он эквивалентен такому определению:
». ПРОЧИЕ ВСТРОЕННЫЕ ПРЕДИКАТЫ 167
повторить.
повторить : —повторить.
Напишем запрос, который целиком" считывает файл "ар. data",
состоящий из термов, и выводит каждый терм иа экран:
\ ?— see ('ар. data'),
repeat,
read (R),
write (R),
R = end_of_file,
!
• >
seen.
% открыть входной файл
% считать терм
% обработать терм
% проверка, нет ли конца файла
% закрыть файл
Нормальный выход из этого цикла может произойти только при
выполнении условия « R = end_of_file» (т.е. по концу файла).
При этом предикат "сократить" ие позволит интерпретатору вер-
вернуться назад.
findall (E, Q, L) Встроенный предикат "findall" ("найти_все") имеется во
многих версиях языка Пролог. Этот предикат вычисляет все ответы
' на запрос и возвращает их в виде списка. Здесь L — список ответов, а
¦ Е - спецификация формы элемента списка L, которая может представ-
представлять собой любой вид терма. Q — это запрос.
Пусть имеется база данных "язык/1" (см. разд. 3.7). Построим прн
помощи предиката "findall" список всех перечислеиных там языков:
! ? - findall (L, язык (L), Список).
Список = [итальянский, немецкий, японский, французский, английский]
Таким образом, действие предиката "findall" заключается в переводе од-
одной формы представления информации (факты) в другую (списки).
В следующем примере параметром Е является структура «обслужи-
«обслуживает (Компания, Б) », которая строится на основании данных, собранных
запросом «путешествие (Компания, А, Б, поезд)».
путешествие (амтрак, нью_йорк, бостон,
путешествие (ндж—транзит, нью_йорк, принстон,
путешествие (амтрак,
путешествие (грейхаунд,
путешествие (амтрак, •
путешествие (пиплз,
путешествие (пиплз,
бостон,
бостон,
нью_йорк,
нью_йорк,
бирлингтон,
поезд).
поезд).
портленд, поезд).
портленд, автобус).
Вашингтон, поезд).
Вашингтон, самолет).
нью_йорк, самолет).
?- findall ( обслужшает (Компания, Б),
L).
путешествие (Компания, А, Б, поезд),
168 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
L = [ обслуживает (амтрак, бостон),
обслуживает (ндж-транзит, принстон),
обслуживает (амтрак, портленд), 4
обслуживает (амтрак, вашингтон)]; л
нет
Примечание: текст одного из вариантов предиката "findall" приведен в при-
приложении II. В некоторых версиях языка Пролог есть встроенные предика-
предикаты "bagof" и "setof", используемые для аналогичных целей.
3.10. ОПЕРАЦИИ
Расширяемость синтаксиса языка Пролог
Внешняя форма синтаксиса языка Пролог расширяема в том смысле,
что предикат или структуру с одним или двумя аргументами можно объя-
объявить операцией. Это достигается путем обращения к встроенному предика-
ту "ор/3".
Предикат или структуру с двумя аргументами можно объявить инфи-
инфиксной операцией. Обозначение инфиксной операции записывается между ее
аргументами, а скобки при этом не нужны. Предикат или структуру с од-
одним аргументом можно объявить либо префиксной, либо постфиксной
операцией.
Ряд операций в языке Пролог определен изначально. Примером встро-
встроенного предиката, являющегося операцией, может служить предикат "is".
Структуры "+","—" и т.д. также являются операциями.
ор (Старшинство, Тип, Имя)
Имя (третий аргумент предиката "ор") должно быть атомом. Обраще-
Обращение к "ор" равнозначно объявлению этого имени названием операции.
«Старшинство» — это число, используемое для того, чтобы избежать-неод-
избежать-неоднозначностей в выражениях, в состав которых входит более одной опера-
операции. Конкретный диапазон допустимых значений старшинства операций
будет зависеть от версии языка Пролог. К примеру, если операция "*" об-
обладает более высоким старшинством, чем операция "+", то будут эквива-
эквивалентными такие выражения:
X + Y*Z
X + (Y * Z)
+ (X,*(Y,Z))
Для изменения порядка выполнения операций, определяемого их старшин-
старшинством, всегда можно воспользоваться скобками.
ЗЛО. ОПЕРАЦИИ 169
Тип может принимать одно из следующих значений:
инфиксные операции xfx xfy yfx _
префиксные операции fx fy
постфиксные операции xf yf
Инфиксная операция "+", обладающая левой ассоциативностью
Операция "+" обладает такими свойствами, как еели бы она была
объявлена следующим образом:
! ?-opE00,yfx,+).
да
Тип yfx означает, что операция "+" обладает свойством левой ассоциатив-
ассоциативности. Так, выражение
A+B + C + D, т.е. +(+(+(А, B),C),D)
можно представить в виде дерева, "растущего" вниз и влево рис. 3.1).
Рис. 3.2
Инфиксная операция ",", обладающая правой ассоциативностью
Операция "," обладает такими свойствами, как если бы она была вве-
введена при помощи объявления:
! ?-ор A000, xfy,,).
да
Тип xfy означает, что операция "," обладает свойством правой ассоциатив-
ассоциативности. Выражение
А, В, C,D т.е. ,(А, , (В, , (С, D)))
можно представить в виде дерева, "растущего" вправо (рис. 3.2).
170 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Инфиксная операция, не обладающая свойством ассоциативности
Тип xfx означает, что операция не обладает ни левой, ни правой ассо-
ассоциативностью- Примером операции этого типа может служить операция
"mod". Поэтому выражение, в котором одно подвыражение с операцией
"mod" выступает в качестве аргумента другого, например,
! ?- X is 120 mod 50 mod 5.
является недопустимым. Такое выражение вызовет выдачу диагност»
ческого сообщения о синтаксической ошибке.
Объявление операций
Еслн Вы составляете процедуру с одним или двумя аргументами, кото-
которой будете часто пользоваться, то можно объявить имя процедуры как
операцию. Наиболее важный критерий, которым следует руководствовать-
руководствоваться при принятии такого решения, - это читабельность программы. Приме-
Применение одних операций будет способствовать улучшению читабельности
программы, в то время как употребление ряда других операций, смысл
которых не столь очевиден, может привести к тому, что в программе
никто, включая самого автора, не сможет разобраться.
В следующей команде "знает" объявляется как инфиксный предикат:
! ?-ор G50, xfx, знает).
да
Теперь факты "знает" можно представлять в текущей программе в инфикс-
инфиксной форме:
джейк знает бетти.
сюзан знает мери.
Запросы к этой базе данных можно также запнсьшать в инфиксной форме:
! ? - X знает мери.
X = сюзан
Условная конструкция "— >"
Еще одним примером операции служит предикат "—>", определение
которого приводится ниже- Этот предикат употребляется некоторыми
программистами как условная конструкция, позволяющая расширить воз-
возможности стандартного соединителя "или", обозначаемого символом ;.
Первым аргументом предиката "— >" является подцель А, а вторым аргу-
аргументом — выражение с соединителем "или", т.е. В; С. Если подцель А ока-
окажется истинной, то далее будет обрабатываться подцель В, а подцель С бу-
3.1 Г. ПРЕОБРАЗОВАНИЕ ПРОЦЕДУРНОГО АЛГОРИТМА 17)
дет проигнорирована. Если же подцель А потрепит неудачу, то будет вы-
выполняться подцель С, а подцель В игнорируется.
! ?- орA101, xfy,->).
да
% читается: если А, то В, иначе С.
(А-> В; С) :-А, !, В.
(А-> В; С) :-С
служащий (джейн).
служащий (салли).
начальник (салли).
] ?— служащий (X),
) начальник (X) —> write (' не приглашать');
write (' пригласить ') ),
write (X), nl,
fail.
пригласить джейн
не приглашать салли
нет
3.11. ПРЕОБРАЗОВАНИЕ ПРОЦЕДУРНОГО АЛГОРИТМА В ПРОГРАММУ
НА ЯЗЫКЕ ПРОЛОГ
Сравнение поиска с возвратом и рекурсии
На языке Пролог могут быть реализованы различные алгоритмические
1етоды, позволяющие добиться того же эффекта, что н итеративные циклы
процедурных языках. Выбор алгоритма зависит от того, как представле-
ы данные, которые требуется обработать (см. табл. 3.1). Если данные
редставлены в виде списка (или рекурсивной структуры иного вида),
о требуется применение рекурсивного алгоритма. Если же данные пред-
гавлены в виде базы данных, содержащей факты, то потребуется исполь-
)вать алгоритм поиска с возвратом.
Таблица 3.1
Представление
факты
рекурсивная
структура
(например, список)
Алгоритм
поиск с возвратом
рекурсия
172 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Цикл "пока"
Рассмотрим в качестве примера спецификацию программы, записан-
записанную на псевдокоде. Эта программа считывает записи "служащий/4" и
суммирует все оклады служащих конкретного отдела. В каждой записи
"служащий/4" содержатся поля с информацией об имени служащего, но-
номере отдела, должности и окладе этого служащего. Спецификация этой
программы имеет вид:
Пока не наступил конец базы данных "служащий/4",
считать запись;
если поле с номером отдела содержит заданный номер,
то добавить к итоговой сумме содержимое поля
"оклад".
При достижении конца базы данных напечатать итоговую сумму.
Рекурсия
Предположим, что база данных "служащий" представлена в виде списка
записей:
% Имя
[ел (брайен,
сл(нэнси,
ел (ральф,
ел (фред,
ел (сюзан,
Отд.
100,
200,
100,
100,
300,
Должность
оператор,
начальник,
менеджер,
техник,
Оклад
20000),
71000),
71500),
29000),
программист,35000) ]
Рекурсивная процедура "ритог_окл" имеет три аргумента: список струк-
структур "ел" (сокращение от "служащий"), номер нужного отдела н итоговую
сумму окладов, выплачиваемую в этом отделе. Первая фраза процедуры
"ритог—окл" — это условие окончания. Она указывает, что рекурсия долж-
должна остановиться, когда список структур "ел" станет пустым. Во второй
фразе выполняется обработка для того случая, когда поле "отдел" первой
записи списка содержит номер нужного отдела. В третьей фразе предусмот-
предусмотрена обработка для случая, когда поле "отдел" первой записи списка не
содержит номера нужного отдела.
ритог_окл ([],-, 0).
% Содержимое поля "отдел" совпадает с нужным номером
ритог_окл([сл(_,Отд,_,Окл) | R], Отд, Итог) : —
ритог_окл (R, Отд, Текущ_сумма),
Итог is Окл + Текущ_сумма.
% Содержимое поля "отдел" не совпадает с нужным номером.
ритог_окл ([сл(_,ХОтд,_,Окл) ! R], Отд, Итог) : -
ХОтд\ = =Отд,
ритог_окл (R, Отд, Итог).
3.11. ПРЕОБРАЗОВАНИЕ ПРОЦЕДУРНОГО АЛГОРИТМА 173
Напишем запрос, который позволит вычислить итоговую сумму окла-
окладов, выплачиваемых в отделе N° 100:
\ ?— рнтог_окл ([ел (брайен, 100,оператор, 20000),
ел (нэнси,200,начальник,71000),
ел (ральф, 100,менеджер,71500),
ел (фред, ЮО.техник,29000),
ел (сюзи, 300,программист, 35000) ],
100, Итог).
Итог = 120500
Поиск с возвратом
Предположим, что имеется база данных, состоящая из фактов "служа-
"служащий/4". Процедура "итог_.окл", приводимая ниже, вычисляет итоговую
еумму окладов, выплачиваемых в определенном отделе. В этой процедуре
рспользуется метод поиска с возвратом. Первое правило процедуры
"итог_окл" осуществляет циклически выбор нового факта "служащий",
удаляет старую текущую сумму, вычисляет новую текущую сумму и до-
добавляет ее как факт "текущ_сумма". (Заметьте, что если бы текущая
сумма вычислялась без употребления предиката "один_раз", то процедура
могла бы возвратиться назад к предикату "retract" и удалить только что
добавленный факт "текущ_сумма". Затем процедура бы зациклилась,
переходя от предиката "assert" к предикату "retract" и обратно.) После
того, как все факты "служащий" будут исчерпаны, первое правило потер-
потерпит неудачу. Следовательно, цель употребления первого правила
"итог__окл" заключается только в том, чтобы оно оказывало побочные
эффекты на текущую программу. Второе правило "итог_окл" просто-на-
просто-напросто выдает текущее значение последней итоговой суммы, содержащееся
в факте "текущ_сумма", и устанавливает новое значение этой суммы,
равное нулю.
% Имя Отд. Должность Оклад
служащий (брайен, 100, оператор, 20000).
служащий (нэнси, 200, начальник, 71000).
служащий (ральф, 100, менеджер, 71500).
служащий (фред, 100, техник, 29000).
служащий (сюзан, 300, программист, 35000).
текущ_сумма @).
итог_окл (Отд, Итог) : — % A)
служащий (_,Отд, _, Окл),
один_раз (retract (текущ_сумма (Сумма) ) ),
Итог is Окл + Сумма,
assert (текущ_сумма (Итог) ),
fail.
174 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
итог—окл (_, Итог) : — % B)
retract (текущ_сумма (Итог) ),
assert (текущ_сумма @) ).
! ? — итог_окл A00, Всего). >4
Всего = 120500 , Ц
Примечание: поскольку факт "текущ_сумма/1" циклически добавляете**
данной программой и удаляется ею, этот факт имеет некоторые черты гло*-
бальной переменной.
Применение предиката "findall"
Для построения списка окладов по всем фактам "служащий", в кото-
которых содержится заданный номер отдела, можно воспользоваться предика-
том"ПпAа11". После того, как этот список будет построен, процедура "сум-'
мировать" сложит вместе все его элементы, что позволит получить итого*'
вую сумму окладов. . ' . R
суммировать ([ ], 0). . т
суммировать ([X i R], Итог) : —
суммировать (R, Сумма), >-
Итог is X + Сумма. .f
Запрос, предназначенный для вычисления итоговой суммы, буде!
иметь вид: '•
I?— findall (Окл, служащий (Имя, 100, Долж.Окл), Список),
суммировать (Список, Итог).
Список = [20000, 71500, 29000]
Итог = 120500
Данное решение, в котором употребляется предикат "findall", будет более
общим (и будет обладать более широкой областью применения), чем
решение, основанное на использовании правила "итог_окл" (см. выше).
БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ
Существуют различные способы объяснения принципов работы реша-
решателя задач, реализованного в Прологе. Наиболее полно это изложено в ра-
работах [25] и [55]. Различные реализации языка Пролог обсуждаются
в работах [14] н [105].
Понятие отрицания как неудачи запроса впервые было сформулирова-
сформулировано в работе [17]. Предположение о замкнутости мира рассматривается
в работах [89] и [78].
Во многих статьях отмечается "коварство" предиката "сократить".
Среди наиболее интересных работ, предостерегающих об опасности употреб-
употребления этого предиката, следует назвать доклад [81]. В работе [58] рас-
УПРАЖНЕНИЯ 175
сказывается об опасностях, связанных с использованием предикатов
"assert" и "retract". Ковальски считает^, что применение предиката
"assert" более оправданно, чем употребление предиката "retract", посколь-
поскольку добавление новых фраз во время выполнения программы в определен-
определенной степени сходно с генерированием лемм (метод доказательства в исчис-
исчислении предикатов). В работах [46] и [58] сравниваются алгоритмы поиска
с возвратом н рекурсивные алгоритмы. В работе [76] дается обзор
"flndall"-подобных предикатов.
УПРАЖНЕНИЯ
1. Запустите интерпретатор языка Пролог и введите факты "путешест-
"путешествие/4" из разд. 1.4. Напишите при помощи предиката "сократить" состав-
составной запрос, который будет находить только один город, в который можно
добраться из Нью-Йорка на транспорте компании Амтрак, а затем будет
отыскивать все города, в которые можно отправиться из найденного города
транспортом данной компании.
2. Напишите обратимую версию процедуры, вычисляющей площадь
прямоугольника (см. упр. 2 из гл. 2). При этом воспользуйтесь предиката-
предикатами var(X) и nonvar(X). Если какие-либо два из трех аргументов этой про-
процедуры будут конкретизированными, то процедура должна вычислять по
ним значение третьего аргумента.
3. Предположим, что имеются две базы данных:
возраст (мери, 16).
возраст (брайен, 17).
возраст (кейт, 15).
возраст (сюзан, 15).
шоферские_курсы (кейт). ,л.-.л .,,.ii ,<¦)• .¦,»>>,',. -,v;.
ШоферСКИе-Курсы(мери). ,,,.,-,,<¦",-,¦<• ¦ ,, :¦> • !»'(•;,
шоферские_курсы (брайен).
Оцените полноту множества ответов и эффективность выполнения для
каждого из приводимых ниже составных запросов. Составной запрос бу-
будет считаться эффективным, если он не тратит понапрасну время на поиск
второго значения возраста для какого-либо лица.
! ? - шоферские_курсы(Х), возраст(X, Y), Y> = 16. %А
] ? - шоферскне_курсы(X), !, возраст(X, Y), Y > = 16. %Б
I ? -шоферские_курсы(Х), возраст(X, Y), !, Y>= 16. %В
,' ? — шоферские_курсы(X), один_раз(возраст(X, Y)), Y> = 16. %Г
Обратитесь к приведенным выше базам данных "возраст" и "шоферс-
кие_курсы". Напишите процедуру "права", которая определяет, что чело-
176 ГЛ. 3. УПРАВЛЕНИЕ ХОДОМ ВЫПОЛНЕНИЯ ПРОГРАММЫ
век может получить водительские права, если ему 16 лет или более и он
прошел обучение на курсах шоферов, либо если ему 17 лет нли более.
4. Придумайте несколько отношений, которые можно описать нега-
негативно, например: "эдШ .1
AiVf
Такси служит транспортным средством для передвижения V,
из пункта А в пункт Б, если
А и Б — это нью-йоркские адреса, и ¦ -'»
ни автобус, ни поезд не курсирует между А и Б.
Машина находится в нормальном состоянии, если
аварийные сигналы не включены. . >¦»¦>.
X является клиентом компании АТ& Т,если
у X есть телефон, и
X не является клиентом ни компании MCI, ни компании Sprint.
Напишите Пролог-программу, в которой будет представлено одно из этих
отношений, при этом воспользуйтесь предикатом "not".
5. Напишите с использованием перидката "repeat" составной запрос,
который спрашивает у пользователя имена школьных товарищей н добав-
добавляет каждое имя в базу данных в виде факта:
школьный_товарищ (Имя).
После того, как пользователь введет слово "конец", запрос должен прекра-
прекратить задавать вопросы и выдать на дисплей все только что введенные
имена.
6. Выберите некоторую форму представления базы данных, в которой
содержатся сведения об операциях с кредитными карточками. Каждая
запись должна содержать сведения об имени лица, тратящего деньги, о типе
операции и о сумме денег. Напишите процедуру, которая будет выдавать
значение итоговой суммы всех операций для конкретного лица.
7. Воспользуйтесь отладочными средствами, чтобы понаблюдать за
выполнением Вашей программы "советник_по_транспорту".
8. Преобразуйте базу данных "путешествие" в список структур. Напи-
Напишите версию процедуры "можнолутешествовать", которая обеспечит
работу с этим списком структур.
9. Напишите версию программы "группа" (см. упр. 3 из гл. 1), кото-
которая будет запрашивать у пользователя сведения о товарищах по группе,
если не сможет найти ответ в базе данных "группа".
При модификации этой процедуры используйте предикаты "var(X)",
"nonvar(X)" и "сократить", чтобы не было возврата назад в том случае,
когда в качестве имени указывается аргумент, не являющийся переменной
(т.е. конкретный человек может числиться только в одной группе). Если
в качесгве имени задается переменная, то возврат назад разрешается.
УПРАЖНЕНИЯ
177
10. Воспользуйтесь предикатами ввода-вьшода для того, чтобы сделать
"дружественным" общение с пользователем одной из написанных Вами
программ.
11. Определите операции^" " и " >" и перепишите процедуру
"можно_путешествовать5" нз разд. 2.2 так, чтобы она выдавала огвет
в следующем виде:
путешествие (амтрак, нью_йорк, бостон, поезд).
путешествие (амтрак, бостон, портленд, поезд).
| ? - можно_путешествовать5 (нью_йорк, портленд, М).
М = нью^йорк — поезд — > бостон — поезд > портленд
I.'.?.-i. Ul* 0>
'¦« . '" .V:.
ГЛАВА 4 i'i'
ПОДХЭДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
ВВЕДЕНИЕ
В первьц четырех главах книги было рассказано об основах языка
Пролог н бьи. рассмотрен ряд примеров, касающихся стиля программирова-
программирования на этом языке. В данной главе обсуждается вопрос о том, как можно
представить себе процесс программирования. В гл. 5, 6 и 7 рассматрива-
рассматриваются конкретные сферы применения языка Пролог.
Три точки зрения на Пролог-программу
Вообще говоря, возможны три точки зрения программиста на Пролог-
программу. Это, во-первых, реляционный подход, при котором программа
рассматрнваегся как множество взаимоопределенных, возможно, очень
сложных, отношений между термами. Во-вторых, существует подход к
программе с позиций потока данных. При этом подходе каждая проце-
процедура связывает друг с другом два или более входных/выходных пото-
потока. Здесь множество ответов, которое вырабатывается в соответствии с
внутренней структурой программы с течением времени в результате вы-
выполнения действий, инициированных запросом, можно рассматривать как
выходной поток данных. (Слово "поток" здесь используется для нестро-
нестрогого определения последовательности элементов.) В-третьих, это - "по-
"поведенческий" (или бихевиористический) подход, согласно которому
программа существует лишь для того, чтобы реализовывать множест-
множество сверхлогичных поведенческих актов, т.е. для выполнения ввода, для
выдачи сообщений и т.д. Эти поведенческие акты также вырабатыва-
вырабатываются с течением времени в соответствии с внутренней структурой прог-
программы в качестве ответа на запрос.
Реляционный подход
Выбор подхода, принимаемого при разработке конкретной компо-
компоненты программы, будет зависеть от того, какой аспект этой компо-
компоненты нашел отражение в ее спецификации (см. табл. 4.1). Реляцион-
Реляционный подход пригоден в том случае, когда хорошо известна структура
предметной области. Процесс программирования при этом сводится к
ВВЕДЕНИЕ
179
известна
Таблица 4.1
Род спецификации и требуемый вид программирования
Что известно
Структура
системы
Выходной по-
поток данных
Поведение
программы
Вид программирования
известен
известно
Аксиоматическое определе-
определение отношений
Создание структуры програм-
программы, обеспечивающей выдачу
нужного потока данных
Создание структуры програм-
программы, обеспечивающей заданное
повгдение
аксиоматическому определению каждого отношения (см. разд. 0.9 и 6.1).
ходной и выходной потоки, а также поведение программы являются
«зультатами действия запросов к отношению. Если отношение реализо-
1ано корректно, то будут правильными также входной и выходной потоки
поведенческие акты программы.
Подход к программе с позиций потока данных
Взгляд на программу с позиций потока данных будет уместным в
ом случае, когда известна природа выходного потока (т.е. множество
гсветов). Прн программировании реализуется такая внутренняя структу-
и программы, которая создает желаемый выходной поток. Если важен
юрядок следования ответов в выходном потоке, то при построении
:рограммы следует в явной форме учитывать процедурные факторы.
Поведенческий подход к программе
Поведенческий подход пригоден тогда, когда известно лишь желае-
юе поведение программы. Процесс программирования связан с построе-
мем такой внутренней структуры программы, которая обеспечит задан-
задание поведение. При разработке такой программы следует обязательно
«читывать процедурные факторы и влияние побочных эффектов.
Сосуществование всех трех подходов
Эти три подхода не являются взаимоисключающими, они представ-
яют собой разные способы мышления в процессе программирования,
точки зрения стиля программирования рекомендуется применять ли-
io реляционный подход, либо подход к программе с позиций потока
180 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
данных, а к поведенческому подходу следует прибегать лишь в случае
крайней необходимости. Причина этого заключается в том, что програм-
программы, при составлении которых применяется поведенческий подход, поч-
почти всегда трудно читать, сопровождать и переводить с одной версии
языка Пролог на другую.
/
4.1. РЕЛЯЦИОННЫЙ ПОДХОД
В соответствии с реляционным подходом основными задачами при
составлении прикладной программы должны быть: анализ значимых сущ-
сущностей и отношений в предметной области, выбор обозначений для пред-
представления всех этих сущностей и отношений, а затем — определение каждо-
каждого отношения при помощи фраз языка Пролог. В гл. 1 рассматривалась
классификация отношений по видам ограничений, обеспечивающих их
целостность (многие-к-мнсгим, один-к-многим, многие-к-одному и один-
к-одному), и по свойствам отношений (симметричность/асимметричность,
рефлексивность/нерефлексивность, транзитивность/нетранзитивность).
После того, как отношение будет точно определено с учетом всех его
свойств и ограничения, обеспечивающего его целостность, это отношение
можно использовать как независимый модуль при определении других
отношений. Хороший пример такого подхода можно найти в разд. 3.3.
Для базы данных "возраст" определяется промежуточная процедура
"мо_возраст", накладывающая ограничение вида многие-к-одному, обес-
обеспечивающее целостность, а затем через процедуру "мо-_возраст" задается
правило "регистрация". Процедуры "мо_возраст" и "регистрация" не за-
зависят друг от друга, так как внутри правила "регистрация" не требуется
размещать дополнительный программный текст, который был бы призван
компенсировать неэффективность или побочные эффекты управления
процедуры "мо_возраст".
Изображение отношений
При анализе бинарных отношений часто оказьшается полезным изобра-
изобразить их графически, когда каждое отношение представляется в виде дуги,
а каждый терм — в виде узла. Такие рисунки показывают связи между
всеми термами. Симметричное отношение между двумя термами изобра-
изображается двунаправленной стрелкой (рис. 4.1). Асимметричное отношение
изображается однонаправленной стрелкой (см. рис. 4.2). Соответственно
асимметричное транзитивное отношение с косвенными связями через
несколько уровней будет выглядеть как дерево, "растущее" вниз (рис. 4.3).
Отношение, являющееся одновременно и симметричным, и транзитивным,
например, отношение "путешествие", будет изображаться так, как показано
на рис. 4.4.
4.1. РЕЛЯЦИОННЫЙ ПОДХОД
С джейн W
V. '
j-
брат_или_сестра.
Рис. 4.1
элис
18»
С б"лл )
Ч
Рис. 4.2
Рис. 4.3
Ограничения, обеспечивающие целостность,
которые накладьшаются при записи отношений в программу
Ограничение, обеспечивающее целостность отношения, может быть на-
наложено либо при записи отношения в программу, либо при выборке этого
отношения.
Если предполагать замкнутость мира, то ограничение, обеспечивающее
Целостность, является свойством конкретного множества фраз, содержа-
182 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
щихся в текущей программе. К примеру, если в текущей программе
имеется только один факт:
отец(билл, даниэль). % A)
то отношение "отец" неявно регулируется ограничением вида один-к-одно-
один-к-одному. Для любого запроса к отношению "отец", в котором первым аргумен-
аргументом будет константа "билл", существует только одно возможное значение
второго аргумента. То же самое справедливо и для любого запроса, вторым
аргументом которого является константа "даниэль". Но если добавить
еще один факт о другом ребенке Билла:
отец (билл, кеннет). % B)
то отношение "отец" неявно станет отношением вида один-к-многим. Это
обусловлено принятым предположением о замкнутости мира. Если в те-
текущую программу по невнимательности программиста попадет еще одно
отношение "отец", вторым аргументом которого является "даниэль":
отец(вильям,даниэль). % C)
то отношение "отец" неявно станет отношением вида многие-к-многим.
Если программа должна зависеть от предположения о замкнутости
мира для ограничений, обеспечивающих целостность отношений, то каждое
ограничение следует вводить в действие в момент добавления новых фраз
в программу.
Ограничения, обеспечивающие целостность,
накладываемые при выборке фраз
Наложение ограничений, обеспечивающих целостность отношений, не-
некоторой промежуточной процедурой при выборке фраз (т.е. при обработке
запроса) служит средством оптимизации вьшолнения запросов в Прологе.
Самый простой способ введения ограничения один-к-одному заключается
в написании процедуры, которая должна выполнить поиск факта, а затем
пройти через предикат "сократить". Приведем пример с версией процеду-
процедуры "отец", в которой накладывается ограничение один-к-одному:
оо-отец (О, Р) : -
отец (О, Р),!.
Поскольку здесь присутствует предикат "сократить", на каждый запрос к
правилу "оо_отец" будет найдено не более одного ответа. Процедура,
накладывающая ограничение один-к-многим на отношение "отец", может
4.1. РЕЛЯЦИОННЫЙ ПОДХОД 183
быть написана по аналогии с процедурой "мо_возраст" из разд. 3.6:
отец (билл, даниэль).
отец (билл, кеннет).
% найти отца конкретного ребенка
% Один Много
ом_отец@, Р ) : - % A)
nonvar (P),
отец (О, Р),!. % "сократить"
% найти в базе данных всех детей конкретного
% отца или все пары отец/ребенок:
ом_отец@,Р) : - % B)
var (P),
отец (О, Р). % нет предиката "сократить"
Ответ на запрос:
] ? - ом_отец (X, даниэль).
X - билл;
нет
получен в соответствии с правилом A). Ответы на запросы:
,' ? - ом_отец (билл, Y).
Y- даниэль ;
Y = кеннет ;
нет
! ?-ом_отец(Х,?).
X = билл
Y - даниэль ;
Х- билл
Y - кеннет ;
получены по правилу B).
Использование в процедуре предиката "сократить" для наложения
ограничений, обеспечивающих целостность отношений, является безопас-
безопасным способом устранения ненужных частей пространства поиска этой
процедуры.
Реализация свойств отношений
Как отмечалось в разд. 1.5, бинарное отношение, реализуемое в языке
Пролог, по умолчанию обладает свойствами рефлексивности, асимметрич-
асимметричности и нетранзитивности. Самый простой способ реализации свойств, от-
184 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
личающихся от принятых по умолчанию— это явное введение в программу
фактов, обеспечивающих соблюдение заданного свойства. Предположим,
к примеру, что в текущей программе содержатся только нижеследующие
факты "брат_или_сестра":
брат_или_сестра (элис, джейн).
брат_или_сестра(дороти, кэти).
Можно сделать отношение "брат_или_сестра" симметричным путем прос-
простого добавления в программу дополнительных фактов "брат_или_сестра"
с обратным порядком следования аргументов:
брат_лли_сестра (джейн, элис). := . т*1 • ft ¦
брат_лли_сестра(кэти, дороти). ¦»-.-„• "'|*
¦>*-... j-\ . ¦¦*т
В соответствии с этим способом симметрию отношения "брат_или_сестра"
может поддерживать программа ввода данных, которая добавляет по два
новых факта "брат_или_сестра" на каждый представленный пользовате-
пользователем факт. Транзитивность отношения (например, отношения "предок")
можно обеспечить аналогичным и столь же громоздким способом.
Альтернативой представлению каждого случая отношения в виде факта
служит применение процедуры, устанавливающей симметричность, не-
нерефлексивность или транзитивность отношения. Так, процедура
"брат_или_сестра2" из разд. 1.3 устанавливает симметрию отношения
"брат_или_сестра", а рекурсивная процедура "предок" устанавливает
транзитивность отношения "предок". Реализация свойств отношения при
помощи процедуры, а не за счет добавления фактов, позволяет добиться
огромной экономии ресурсов. В следующих разделах детально обсуждается
реализация свойств отношений, не рассматривавшихся в гл. 1.
Нерефлексивность
В разд. 1.3 было отмечено, что отношение "знает2" обладает ненужной
рефлексивностью, так как будет успешным, к примеру, запрос:
] ?— знает2(мери, мери).
да
Отношение "знает" можно превратить в нерефлексивное путем добавления
еще одной подцели:
знаетЗ(А, В) : -
раб_смена (А, Смена),
раб_смена (В, Смена),
А\ = =В.
4.1. РЕЛЯЦИОННЫЙ ПОДХОД 185
Симметричное и транзитивное отношение
Пока еще мы не смогли адекватно представить отношение, которое
являлось бы одновременно и симметричным" и транзитивным. В разд. 1.5
была рассмотрена версия процедуры "можно_путешествовать", названная
"можно_путешествовать4", которая обладала свойством транзитивности,
но не была симметричной, т.е. в ней допускается поездка из Нью-Йорка в
Бостон, но не из Бостона в Нью-Йорк. Данные (т.е. база данных, состоящая
из фактов "путешествие/4") были тщательно подобраны, чтобы не до-
допустить появления циклов. К примеру, в базе данных имеются факты, опи-
описывающие возможность добраться из Бирлингтона в Нью-Йорк и из
Нью-Йорка в Бостон, но нет факта, описывающего путешествие из Бостона
в Бирлингтон. Отсутствие симметрии и необходимость в данных без циклов
являются серьезными недостатками процедуры "можно_путешество-
вать4". Хотелось бы написать такую версию процедуры "можно_путешест-
вовать", которая обладала бы симметричностью и позволяла бы обрабаты-
обрабатывать любые данные.
Первая попытка
Один из подходов к решению этой задачи заключается в том, чтобы сде-
сделать базу данных "путешествие" симметричной, пользуясь тем же методом,
который был применен для базы данных "брат_лли_сестра", а затем
обратиться к базе "путешествие" из рекурсивной процедуры "можно_пу-
тешествовать". Правило "можно_путешествовать" в этом случае автомати-
автоматически унаследует симметрию базы данных "путешествие". Кроме того,
добавим в него подцель А \ = = Б, что позволит сделать отношение не-
нерефлексивным и, следовательно, даст возможность избавиться от неко-
некоторых ошибочных ответов. Получившуюся процедуру назовем "тснр_пу-
тешествоватьГ' ("тснр" означает транзитивное, симметричное, нерефлек-
нерефлексивное отношение).
% Либо один вид транспорта соединяет пункты А и Б:
тснр_путешествовать1 (А, Б, м(Вид_тр,Б)) : —
А\ = =Б
сим_путешествие (А, Б, Вид_тр).
% Либо более, чем один вид транспорта соединяет А и Б:
тснр_путешествовать1 (А, Б, м(Вид_тр1,В,Вид—тр2)) : —
А\ = = Б,
сим_путешествие (А, В, Вид_тр1), ^*
тснр_путешествовать1 (В, Б, Вид_тр2).
% Промежуточная процедура, обеспечивающая симметрию
% фактов, содержащихся в базе данных "путешествие"
сим_путешествие (А, Б, Вид_тр) : — путешествие (А, Б, Вид_тр).
184 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
сим_путешествие (А, Б, Вид_тр) : — путешествие (Б, А, Вид_тр).
% Из В Вид_транспорта
путешествие (манхэттен, ньюарк, автобус).
путешествие (манхэттен, куинс, жел_дорога).
Здесь "путешествие" — это явная база данных, в которой хранятся фак-
фактические данные. Для простоты в этой версии базы данных отсутствует
аргумент с названием транспортной компании. Если мы выдадим запрос
к процедуре "тснр_путешествовать1" по поводу того, как можно добрать-
добраться из Ньюарка в Куинс, то первый ответ на него будет приемлемым:
i ? - тснр_путешествовать 1 (ньюарк, куинс, М).
М - м {автобус,манхэттен, м {жел^дорога, куинс) );
Однако, кажется, существует бесконечное количество дополнительных от-
ответов, ценность которых весьма сомнительна:
М = м {автобус,манхэттен, м {автобус, ньюарк,
м {автобус,манхэттен, м {жел ^дорога, куинс) ) ) ) ;
М-м{автобус.манхэттен, м{автобус,ньюарк,
м {автобус.манхэттен, м {автобус,ньюарк,
м(еетобус,манхэттен, м{жел-дорога,куинс)))))) ;
М = м {автобус,манхэттен, м {автобус,ньюарк,
м {автобус.манхэттен, м {автобус,ньюарк,
м {автобус.манхэттен, м {автобус,ньюарк,
м {ав тобус, манхэттен, м {жел ^дорога, куинс)))))))) ;
Каждый раз, когда мы запрашиваем другой ответ, процедура совершает
еще один цикл между Манхэттеном и Ньюарком, прежде чем в конце
концов доходит до Куинса! Данные теперь обладают "врожденной"
цикличностью, так как процедура "сим—путешествие" симметрична. Запрос
к тснр_путешествовать1" тонет в ненужных циклических действиях.
Вторая попытка
Можно избежать циклических перемещений между Ньюарком и Ман-
Манхэттеном. Для этого нужно принять, что если имеется прямой маршрут
между пунктами А и Б, то не следует искать какие-либо дополнитель-
дополнительные ответы. Иными словами, если первое правило процедуры "тснр_пу-
тешествоватьГ' окажется успешным, то предикат "сократить" должен воо-
препятствовать переходу ко второму правилу. Позабудем на время об
опасностях, связанных с употреблением предиката "сократить", и попы-
попытаемся определить, устранит ли наличие этого предиката возникшие
циклические перемещения. Новую версию процедуры назовем "тсир_пу-
4.1. РЕЛЯЦИОННЫЙ ПОДХОД 187
тешествовать2":
% Либо один вид транспорта соединяет пункты А и Б:
тснр_путешествовать2(А, Б, м(Вид_тр,Б) : —
А\ = =Б,
сим_путешествие (А, Б, Вид_тр),!. % добавлен "!"
% Либо более чем один вид транспорта соединяет А и Б :
тснр_путешествовать2(А, Б, м(Вид_тр1,В,Вид_тр2)) : —
А\ = =Б,
сим_путешествие (А, В, Вид_тр1),
тснр_путешествовать2 (В, Б, Вид—тр2).
Если "сим_путешествие" и "путешествие" имеют тот же вид, что и в пре-
предыдущей программе, то ответ на тот же запрос, что и ранее, будет впол-
вполне разумным:
! ?— тснр__путешествовать2(ньюарк, куинс, М) .
М = м (автобус,манхэттен, м (жел—дорога, куинс) );
нет
Интуитивно мы представляем, что на этот запрос должен даваться толь-
только один ответ, и программа находит его.
Но представим себе, что в базу данных "путешествие" будет добав-
добавлено всего лишь несколько новых фактов, дающих более подробную
картину транспортной сети данной местности. Теперь в базе данных "пу-
"путешествие" будут содержаться факты:
путешествие (манхэттен, ньюарк, автобус),
путешествие (манхэттен, куинс, жел_дорога).
путешествие (ньюарк, бронкс, автомобиль),
путешествие (бронкс, куинс, автобус).
путешествие (манхэттен, бронкс, метро),
путешествие (ньюарк, принстон, автомобиль),
путешествие (манхэттен, принстон, автобус).
Эти факты можно представить графически (см. рис. 4.5).
Результаты выполнения того же самого запроса к "тснр_путешест-
вовать2" при расширенной базе данных опять обескураживают:
! ?— тснр_путешествовать2 (ньюарк, куинс, М).
М = м (автомобиль, брокнс, м (автобус, куинс) );
М = м (автомобиль,принстон, м (автомобиль,ньюарк,
м(автомобиль,брокнс, м(автобус,куинс))));
М-м(автомобиль,принстон, м(автомобиль, ньюарк,
м (автомобиль,принстон, м (автомобиль, ньюарк,
м (автомобиль, бронкс, м (автобус, куинс))))));
188
ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
автомобиль /автобус
автомобиль
Г приметой
Рис. 4.5 -
Добавление предиката "сократить", как кажется, позволило устранить
циклические перемещения только для случая, когда в базе данных "путе-
"путешествие" было всего два факта. Помимо этого, предикат "сократить"
представляет опасность и в том отношении, что при его использовании
могут быть отброшены и правильные ответы. Если бы между двумя пункта-
пунктами курсиров!ал более чем один вид транспорта, то процедура "тснр_путе-
шествовать2" смогла бы найти лишь первый из них. Множество ответов
также является неполным. Поскольку процедура "тснр_путешествовать2"
стала циклически перемещаться между Ньюарком и Принстоном, она ни-
никогда не дойдет до более удобного маршрута из Ньюарка в Куинс через
Манхэттен.
Опять-таки данные обладают цикличностью, и запрос "вязнет" в одном
из циклов. Существуют два способа борьбы с таким поведением програм-
программы: либо тщательно проверить все данные на отсутствие циклов, либо
сделать программу нечувствительной к цикличности данных. Второй способ
предпочтителен по ряду практических соображений. В данном случае нужно
сделать так, чтобы процедура "тснр_путешествовать" не возвращалась в
то место, где она уже побывала.
Запоминание списка посещенных мест
В третьей версии процедуры "тснр_путешествовать" применяется но-
новая стратегия, позволяющая избежать увязания в цикле. В этой программе
запоминается список посещенных мест. Программа не возвращается к тому
месту, где она уже побывала.
Первым аргументом процедуры "тснр_путешествоватьЗ" является
список всех посещенных мест. В соответствии со вторым правилом этой
4.1. РЕЛЯЦИОННЫЙ ПОДХОД 189
процедуры, после того, как подцель "сим_путешествие" сгенерирует но-
новый промежуточный пункт В, подцель "элемент" выполнит проверку
того, чтобы В не содержался в списке мест, которые уже были посещены.
Если В — новый пункт, то он добавляется в начало списка при помощи
рекурсивного обращения к процедуре тар_путешествоватьЗ", так что
при любых последующих рекурсивных вызовах этой процедуры В не будет
приниматься в качестве промежуточного пункта. Промежуточная процеду-
процедура "путешествиеЗ" преобразует три исходных аргумента в четыре аргумен-
аргумента, которые требуются в процедуре "тснр_путешествоватьЗ". При первом
вызове процедуры "тснр_путешествоватьЗ" исходный пункт А помещается
в список посещенных мест. Процедура "сим_путешествие" и база данных
"путешествие" остались такими же, как и ранее.
% Промежуточная процедура для "тснр_путешествоватьЗ" х
% + + -
путешествиеЗ (А, Б, М) : —
тснр_путешествоватьЗ ([А], А, Б, М). % Добавить А к
% След.
% Либо один вид транспорта соединяет пункты А и Б:
; % + + + -
тснр_путешествоватьЗ(След, А, Б, м(Вид_тр,Б)) : — % (О
А\==Б,
сим_путешествие (А, Б, Вид_тр).
% Либо более чем один вид транспорта соединяет пункты
% А и Б (т.е. нужны пересадки) :
% + + + -
тснр_путешествоватьЗ (След, А, Б, м(Вид_тр1,В,Ввд_тр2)) ;_ % B)
А\ = =Б,
сим_путешествие (А, В, Вид_тр1), % сгенерировать В
not (элемент(В, След)), % проверка В
тснр_путешествоватьЗ ([В ] След], В, Б, Вид_тр2).
Посмотрим, как данная процедура будет обрабатывать все тот же запрос
] ?— тснр_путешествоватьЗ(ньюарк, куинс, М).
М=м(автомобиль,бронкс, м(автобус, куинс)) ;
М~м (автомобиль, бронкс,
м (метро, манхэгтен, м (жел -дорога, куинс))) ;
М = м (автомобиль, принстон,
м (автобус, манхэттен, м (жел-дорога, куинс) ) ) ;
М = м (автомобиль, принстон, м (автобус, манхэттен,
м (метро, бронкс, м (автобус, куинс)))) ;
190 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
М = м (автобус, манхэттен, м (жел-.дорога, куинс)) ;
М = м (автобус, манхэттен,
м (метро, бронкс, м (автобус, куинс) )) ;
нет
Если Вы изучите рис. 4.5, то обнаружите, что данная программа выдает
все правильные ответы, включая наиболее разумный ответ (проехать ав-
автобусом до Манхэттена, а затем — поездом Лонг-Айлендской железной
дороги до' Куинса). Итак, причинами успешной работы процедуры
"тснр_путешествоватьЗ" являются следующие обстоятельства:
1) эта процедура, как было показано, симметрична, транзитивна и не-
нерефлексивна;
2) запрос к процедуре позволяет получить полное множество ответов;
3) при запросе о том, как добраться из Куинса в Ньюарк, будет полу-
получено множество ответов, являющееся зеркальным отображением мно-
множества ответов на запрос о том, как добраться из Нюарка в Куинс..
Следующим шагом в разработке данной программы может стать прис-
присваивание каждому прямому маршруту между пунктами некоторых весо-
весовых коэффициентов, соответствующих расстоянию между ними или затра-
затратам времени на преодоление этого расстояния. Программа может выбрать
наилучший маршрут по критерию наименьшего времени, по критерию
наикратчайшего пути или в соответствии с определенным комбинирован-
комбинированным критерием, учитывающим эти факторы (см. упр. 1 в конце данной
главы).
4.2. ВЗГЛЯД НА ПРОГРАММУ
С ТОЧКИ ЗРЕНИЯ ПОТОКА ДАННЫХ
Переход от выходного потока данных к программе
В соответствии с подходом к программе с позиций потока данных,
множество ответов (или выходной поток данных) программы выраба-
вырабатывается в соответствии с внутренней структурой программы в результа-
результате выполнения запроса. Если множество ответов будет известно заранее,
то составление программы сведется к реализации такой ее внутренней
структуры, которая обеспечит выдачу этих ответов. Назначение программы
состоит именно в генерировании заданного множества ответов, а то, ка-
каким образом это достигается, не имеет значения. Программа может выра-
вырабатывать множество ответов либо в качестве реакции на входной поток
данных, поступающих во время выполнения программы (т.е. представ-
представленный как аргумент запроса), либо при обращении к другим фразам те-
текущей программы. После того, как программа, генерирующая заданное
множество ответов, будет написана, ее можно использовать в качестве
модуля при составлении других программ.
4.2. ВЗГЛЯД НА ПРОГРАММУ С ТОЧКИ ЗРЕНИЯ ПОТОКА ДАННЫХ 191
В гл. 3 рассматривались два основных семейства алгоритмов, исполь-
используемых в Пролог-программах, — алгоритмы поиска с возвратом и рекур-
рекурсивные алгоритмы. Для многих типов задач эти виды алгоритмов одина-
одинаково эффективны. В оставшейся части данного раздела продемонстрируем
реализацию подхода к программе с позиций потока данных с примерами
употребления обоих видов алгоритмов.
Множество ответов программы — зто множество значений, вырабаты-
вырабатываемых программой при определенных условиях, которые специфицируют-
специфицируются запросом и множеством всех фраз, содержащихся в текущей программе.
Рассмотрим тривиальный пример. Пусть спецификация множества ответов
заключается в следующем: если номер отдела равен 100, то программа
должна выдавать имена служащих — Брайен и Ральф. Простейшая програм-
программа, удовлетворяющая этой спецификации, состоит всего из двух фраз:
служащий (брайен, 100).
служащий (ральф, 100).
Запрос:
! ?- служащий (Имя, 100).
приведет к выдаче значений:
Имя = брайен ;
Имя = ральф
Упорядоченные множества ответов
Важной характеристикой множества ответов является то, имеет ли зна-
значение порядок ответов. Для программы "служащий", приведенной выше,
Порядок следования ответов не имеет никакого значения. Теперь рассмот-
рассмотрим программу, множеством ответов которой является упорядоченное
^множество четырехбитовых двоичных чисел - от 0000 до 1111.
' Генератор двоичных чисел
I Тогда запрос:
[ : ?- число (А, В, С, D). % A)
it-
(рлжен выдавать при помощи конкретизированных переменных цифры
(воичного числа. Каждый раз, когда пользователь вводит символ ; , запрос
Юлжен вырабатывать следующее по порядку двоичное число. Первым от-
етом должно быть:
192 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
Следующий ответ должен быть таким:
А = 0
и т.д. Простейший способ генерирования такого множества ответов заклю-
заключается в определении упорядоченного множества фактов "число":
число @,0,0,0).
число @,0,0,1).
число @,0,1,0).
число @,0,1,1).
число @,1,0,0).
число A,1,1,1).
Запрос A), приведенный выше, будет каждый раз, возвращаясь . назад,
вырабатывать нужные ответы. Однако можно добиться точно таких же
результатов и при помощи гораздо более компактной процедуры.
Множество ответов здесь эквивалентно некоторому шаблону, в кото-
котором чередуются нули и единицы, поэтому начнем с написания простой про-
процедуры, которая выдает попеременно то нуль, то единицу:
цифра @).
цифра A).
Затем нужно составить правило "двоичн_число", которое четыре раза вы-
зывает процедуру "цифра":
двоичн_число (А, В, С, D) :— , ,.,
цифра (А), цифра (В), цифра (С), цифра (D). ,,
Вы самостоятельно сможете понять, какие результаты принесет запрос к
этому правилу. Это правило будет выполнять точно такие же действия,
как и четыре вложенных цикла "пока" ("while") в процедурном языке:
А=0
while А < = 1 begin
В = 0
while В < = 1 begin '
С = 0 ¦ "
while С < = 1 begin ',
D = 0
while D<= 1 begin ;
print А В С D 5
D = D + 1
end
4.2. ВЗГЛЯД НА ПРОГРАММУ С ТОЧКИ ЗРЕНИЯ ПОТОКА ДАННЫХ 193
С = С+ 1
end * .
В=В +1
end
А = А+ 1
end
В множестве ответов насчитывается ровно 16 элементов. Приведенное пра-
правило "двоичн_число" потерпит неудачу, если пользователь запросит еще
один ответ, когда переменные А, В, С и D конкретизированы значением 1.
Генерирование бесконечного множества
Предположим, что требуется, чтобы множество ответов предыдущей
программы стало бесконечным за счет повторения опять и опять преды-
предыдущего набора из шестнадцати ответов. После того, как будет получена
совокупность из четырех единиц, следует опять перейти к четырем нулям
и продолжить счет. Для того чтобы процедура "двоичн_число" стала удов-
удовлетворять этим требованиям, нужно модифицировать ее путем добавления
еще одной подцели:
бесконечн_двоичн_число (А, В, С, D) : -
repeat,
цифр;!(л),цифра(В),цифра(С),цифра(О). '
Подцель «repeat» работает следующим o6p;i ом. Пусть пользователь
ввел символ ;, запрашивая другой ответ, причем переменные А, В, С, D
конкретизированы значением 1. Интерпретатор возвратится на :ад (влево
от подцели «цифраф)») до предиката «repeat». Затем он снова начнет
выдачу ответов, причем начальными значениями переменных А, В, С и D
будут нули.
Экологаческий процесс
В этом примере каждый ответ является сообщением об относитель-
относительном размере популяций хищников и их добычи в гипотетической экологи-
экологической ситуации. Эти две популяции связаны друг с другом следующим
образом:
- увеличение популяции добычи вызывает рост популяции хищников
на протяжении следующего периода времени {поскольку количество
пищи для хищников увеличивается);
- увеличение популяции хищников приводит к уменьшению популя-
популяции их добычи на протяжении следующего периода времени (потому что
появляется большее число хищников, поедающих добычу);
- уменьшение популяции добычи вызывает снижение размера попу-
популяции хищников на протяжении следующего периода времени (так как
объем пищи хищников уменьшился);
7- Дж. Малпас
194 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛО1
- уменьшение размера популяции хищников приводит к увеличению
популяции добычи в течение следующего периода времени {ввиду того,
что меньшее числа хищников охотится за своими жертвами)
- и т.д.
Мы ходим получить бесконечное множество ответов в соответствии с
данным циклом.
Версия программы, в которой применяется поиск с возвратом
Самый простой путь получения данного множества ответов — это
введение в программу четырех фактов, описывающих относительные раз-
размеры популяций хищников и их жертв, по одному факту на каждую фазу
цикла. Важен порядок, в котором записываются факты, так.как он должен
соответствовать порядку следования фаз цикла. Первый аргумент каждо-
каждого факта "'популяция" описывает состояние популяции добычи, а второй
аргумент - состояние популяции хищников.
% Добыча Хищники .
популяция (рост, безизменений).
популяция (безизменений, рост).
популяция(уменьшение, без изменений).
популяция (безизменений, уменьшение).
Приведенный ниже составной запрос к этой базе данных будет выполнять-
выполняться циклически до бесконечности:
! ?— repeat, популяция(Добыча, Хищники).
Добыча = рост
Хищники = без ^изменений ; •
Добыча = без _изменений
Хищники -рост ;
Добыча = уменьшение
Хищники = без^изменений ;
Добыча = без _изменений
Хищники = уменьшение ;
Добыча =рост
Хищники = без изменений ;
и т.д. Схема ответов соответствует временным фазам состояния эко-
экосистемы. *'•
¦'. л-uv
4.2. ВЗГЛЯД НА ПРОГРАММУ С ТОЧКИ ЗРЕНИЯ ПОТОКА ДАННЫХ 195
Рекурсивная версия программы
Можно получить это же множество ответов и при помощи рекурсив-
рекурсивной процедуры. Начнем с определения базы данных, содержащей информа-
информацию о переходах экологической модели из одних состояний в другие.
Первым аргументом каждого факта "переход" является структура "б",
характеризующая баланс популяций "добыча"/"хищники" в текущем
состоянии системы, а вторым аргументом служит такая же структура,
характеризующая последующее состояние этой системы. Предполагается,
что ситуация, сложившаяся в текущем состоянии, с необходимостью вызы-
вызывает переход к другой ситуации в следующем состоянии.
i М
[ % Текущее состояние Следующее состояние
I "Ji добыча хищники добыча хищники ! *
переход (б (рост, безизмеиений), б (без изменений, рост)). г'
переход(б(без_изменений, рост), б(уменьшение, без изменений)). ''
переход (б (уменьшение, безизменений), б(без изменений. ''
уменьшение)).
переход(б(без изменений, уменьшение), 6(p<vt, без изменений)). f .
. Первым аргументом рекурсивной процедуры "рпоп" (сокращение от
слов "рекурсивная популяция") является структура "б", представляющая
начальное состгяние баланса "добыча"/"хищники", а вторым аргументом
служит структура "б", представляющая следующее состояние этого ба-
баланса.
% Имена переменных:
% Тдоб - текущая популяция добычи; ,¦ »
% Тхищ - текущая популяция хищников; _ »
Сдоб - популяция добычи в следующий период времени;
Схищ - популяция хищников в следующий период времени.
+
юн (б (Тдоб, Тхищ), б (Сдоб, Схищ)) :- , % A)
переход (б (Тдоб, Тхищ), б(Сдоб, Схищ)). >г «
рпоп(б(Тдоб, Тхищ),б(Сдоб1,Схищ1)) :- 8й,: % B)
переход(б(Тдоб, Тхищ), б(СдобО, СхищО)), ж '
рпоп(б(СдобО, СхищО),б(Сдоб1,СхищП). .ш
Правило A) только лишь отыскивает факт "переход" с требуемым первым
фгументом и возвращает второй аргумент этого факта. Правило B)
находит тот же самый факт "переход", а затем выполняет рекурсивный
вызов процедуры "рпоп", при котором второй аргумент найденного факта
служит первым аргументом этой процедуры. Запишем запрос к процедуре
196 ГЛ.4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРСМЦИ"
"рпоп", начиная с точки, в которой популяция добычи уменьшается:
! ?- рпоп( б (уменьшение,), б(Доб, Хищ)).
Доб = без изменении . •> '
Хищ = уменьшение; %Фаза1 ,, ., <>
Доб = рост . „, , |с (I „ i .
Хищ = без изменений ; % Фаза 2 ,,'* Л „(>, , ,
Доб = без_изменений ' ¦* **' '» "'
Хищ = рост ; %ФазаЗ М<К» l ,««' ""» "н
Доб = уменьшение
= без изменении ; ' - • . % Фаза 4
= без изменений " '
Хищ = уменьшение \ » % Фаза 5, '¦< <¦ "
%совпадает с фазой 1.
В рекурсивной процедуре "рпоп" (в отличие от процедуры "популя-
"популяция", в которой использован алгоритм поиска с возвратом) порядок следо-
следования ответов не зависит от порядка, в котором расположены факты
"переход", поскольку для каждого из этих фактов выполняется сопостав-
сопоставление с эталоном. Здесь каждый факт выражает причинную связь между
двумя состояниями экосистемы. В программе, которая более точно моде-
моделировала бы экологический процесс, каждый факт "переход" можно
было бы превратить в правило. К примеру, можно было бы ввести пра-
правило "переход", которое не допускало бы увеличения популяции хищни-
хищников, если бы местные власти поощряли охоту на хищников. Другое пра-
правило могло бы разрешить рост популяции добычи только в том случае,
когда имеется достаточно пищи и воды:
% Текущее состояние Следующее состояние
% добыча хищники добыча хищники
переход( б(без_изменений, уменьшение), б(рост, без_изменений) : —
текущийсезон (Сезон), т)
достаточно пищи (добыча. Сезон), О к/i .*•'•,! irTsnof!,
достаточно воды (Сезон). m> .ifviirmi»
В обеих приведенных версиях программы (рекурсивная версия и
версия, в которой применяется поиск с возвратом) будет вырабатывать-
вырабатываться бесконечное множество ответов. Однако рекурсивная версия потребует
большего объема памяти, и в некоторых версиях Пролога она, закончит-
закончится аварийно, когда интерпретатор исчерпает доступную ему стековую
память.
.. . '•,-¦!' Ч.'".И .'И'1' :-. i 'С,:.;!'! •/:'>" ••:'¦< • ¦: у ' ¦ Л1'\ -!: *?1'-71'"П Я'
Ы f»A hi-Or № ¦¦¦¦¦ ч" ->**•
4.2. ВЗГЛЗД^ ГОрГРАММУ С ТОЧКИ ЗРЕНИЯ ПОТОКА ДАННЫХ Щ,
. ,.,, Описание множества ответов ' . .
Про множество ответов на запрос к процедурам "популяция" и "рпоп"
можно сказать, что оно представляет из себя цикл, состоящий из четырех
фаз. За один раз выдаются два интересующих нас ответа, которые пере-
переешаются по этому циклу со смещением на одну фазу друг относительно
ipyra. Порядок выдаваемых ответов соответствует нормальному ходу
реме ни.
Планирование производственных операций
Последний пример данного раздела связан с планированием работ в
роизводственном процессе. Множество ответов описываемой программы
:аьл<е подчинено циклическому закону, а количество фаз цикла равно
к1 у станков, занятых в производственном процессе. Каждый ответ,
ыдаваемый программой, является списком, который описывает место-
ихождение всех изготавливаемых изделий в конкретный момент времени.
Для простоты будем считать, что в производственном процессе участ-
уют только три станка - «станок1», «станок2» и «станокЗ». Предпо-
ожим, что нужно изготовить три изделия - А, Б и В. За один интервал
ремени станок может обработать только одно изделие. При переходе
>т одного интервала времени к другому все изделия перемещаются к
:лёдующим по производственному циклу станкам. До того, как изделие
[опадает на первый станок, оно считается не сделанным. После того
сак изделие пройдет полный цикл обработки, оно считается изготовлен-
1ым. Множество ответов изображено в табл. 4.2.
В программе, которая должна вырабатывать данное множество от-
етов, используется несколько необычный рекурсивный алгоритм. Вна-
але нужно представить переходы между состоянием "не сделано "(со сто я-
1ие изделия перед началом обработки), тремя стадиями обработки на
Таблица 4.2
Перемещение изделий с течением времени
изделие А
изделие Б
изделие В
интервал 1 не сделано не сделано не сделано
интервал 2 станок 1 "; не сделано '' ' не сделано
интервал 3 станок 2 ;,.«! станок! . не сделано
интервал 4 станок 3 станок 2 станок 1
интервал 5 изготовлено станок 3 станок 2
интервал 6 изготовлено изготовлено станок 3
интервап 7 изготовлено изготовлено изготовлено
198 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
станках и состоянием изготовлено (состояние
обработки):
% От
переход (не сделано,
* переход(не_ сделано.
v переход (станок 1,
переход (станок2,
переход (станокЗ,
переход (изготовлено,
К
не сделано).
станок1). '.
изделия после завершения
>! ОНО ОТ
станок2). тикаешь
станокЗ).
изготовлено).
изготовлено).
11у3«к(»1.м щи
tu'i . HMjUO it
'ИГ, <.'!! «SO)*'
$
! Первый факт "переход" необходим для того, чтобы изделие могло
находиться в состоянии «не сделано» до тех пор, пока не освободится
«станок 1». Последний факт позволяет сохранить изделие в состоянии
«изготовлено» после того, как оно пройдет весь цикл обработки. В про-
процедуре "поток изделий'' первым аргументом является список изделий,
а вторым - выходным - аргументом служит список структур "сост".
описывающих местонахождение каждого изделия.
% имена переменных: ,,'-,,
, % А, В - изделия
"и %S1, S2 - станки
% Список изделий Местонахождение изделий
'п % +
и поток_изделий( [А, В ] Остаток], [сост(А, S1), сост(В, S2) 1 Изд1),:-
к nepexofl(S2,Sl), ц
р. поток_изделий( [В ! Остаток], [сост (В, S2) | Изд]). /,ц;5Я-
»( % Последнее изделие в списке: *: '•'
поток_изделий([А], [coct(A,S1)) : - ;.ш<!:
переход(, S1).
Подцель "переход" осуществляет поиск с возвратом по фактам
"переход", чтобы показать продвижение одного изделия по стадиям про-
производственного процесса. Процедура "поток изделий" рекурсивно вы-
выдвигает столько подцелей "переход", сколько насчитывается изделий во
входном списке. Она также обеспечивает то, чтобы положение некоторого
изделия в производственном цикле всегда отставало на одну стадию от
положения другого изделия, стоящего во входном списке перед данным.
В нижеследующем запросе представлены для обработки три изделия:
! ?— поток изделий ([изделиеА,изделиеБ, изделиеВ], Т).
Т = [сост{изделиеА, переделано), сост {изделие Б, не сделано),
сост(изделиеВ, не сделано)] ;
Т= [сост (изделие А, станок!), сост (изделиеБ, не ^сделано),
сост (изделиеВ, не сделано)] ;
4.2. ВЗГЛЯД НА ПРОГРАММУ С ТОЧКИ ЗРЕНИЯ ПОТОКА ДАННЫХ 199
Т= \сост{изделиеА, станок!), сост (изделиеБ, станок!),
сост (изделиеВ, не сделано)] ; "• '':>ч "
Т= [сост(изделие:А, станокЗ), сост{изделиеБ, станок!), ,.
сост(изделиеВ, станок!)] ; ^
Г = [сост (изделиеА, изготовлено), сост (изделиеБ, станокЗ), >
сост (изделиеВ, станок2)] ;
!< Г= [сост (изделие А, изготовлено), сост (изделиеБ, изготовлено), "
сост (изделиеВ, станокЗ)] ;
Г = [сост (изделиеА, изготовлено), сост (изделиеБ, изготовлено),
сост(изделиеВ, изготовлено)} ;
Ясно, что данная модель является моделью крайне простого произ-
юдственного процесса. Однако примененный здесь подход можно сделать
Я>лее общим, если превратить факты "переход" в правила. К примеру,
юток изделий от станка 1 к станку2 может зависеть от количества рабо-
шх, занятых на станке1. В показательном примере (см. приложение III)
шанирование производственных операций осуществляется ? большей
непенью детализации.
,» , i
Сильные и слабые стороны подхода «м *.. •>
к программе с позиций потока данных , ' *г.
Одним из преимуществ взгляда на программу с точки зрения потока
данных является то, что программист вынужден постоянно обращать вни-
внимание на правильность и полноту ответов, вырабатываемых программой.
При реляционном подходе существует возможность написания такой
программы, которая представляется точным описанием структуры пред-
предметной области, но не генерирует должного множества ответов. Примером
такой программы служит программа "тснрпутешествоватьГ'из разд. 4.1.
Если подходить с позиций потока данных, то эта программа является со-
совершенно неудачной.
С точки зрения потока данных две программы будут взаимозаменяе-
взаимозаменяемыми, если они вырабатывают одинаковое множество ответов; различия
во внутренней структуре этих программ не имеют значения. Такое пред-
представление о программах позволяет упростить процесс разработки сложных
программ нисходящим методом. Предположим, что программу можно
разбить на отдельные компоненты, а множества ответов, вырабатывае-
вырабатываемые каждой компонентой, известны. На ранних стадиях разработки про-
программы роль компоненты может играть множество фактов. Позднее такую
компоненту можно будет заменить на процедуру, в которой учитываются
дополнительные условия и уточнения для множества ответов.
Если важен порядок следования элементов множества ответов, то
при написании программы необходимо учитывать процедурную семанти-
200 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
ческую модель. Пролог-программу можно рассматривать как аксиомати-
аксиоматическое определение ее множества ответов, при этом каждая фраза програм-
программы эквивалентна аксиоме. Если подходить с процедурных позиций, то
фраза — это последовательность шагов, необходимых для того, чтобы
сгенерировать элемент множества ответов или наложить определенные
ограничения на этот элемент. Совокупность фраз представляет собой метод
определения элемента множества ответов и построения этого множества
в целом. . ,
,^,,пД-» 4.3. Б11ХЕВИОРИСТИЧЕСКИЙ ПОДХОД '
.„^.л Приведенные ранее примеры,
в которых проявился бихевиориэтический подход -. '¦"
Программист, пишущий программу с той 1,пью, чтобы воспользо-
воспользоваться побочными эффектами ее поведения, и не учитывающий реляцион-
реляционные факторы или структуру множества ответов, реализует бихевиористи-
ческий (или поведенческий) подход к программированию. Примером
программы, написанной в соответствии с бихевиористическим подходом,
может служить программа "место" из разд. 3.7. Когда эта программа не
может найти место расположения какого либо объекта по базе данных
"адрес", она не просто завершается неудачно, а просит пользователя сооб-
сообщить адрес этого объекта. Другими программами из гл. 3, написанными
в соответствии с бихевиористическим подходом, являются процедура
"изменить терминал" (см. разд. 3.7) и составной запрос о языках (см.
разд. 3.7).
Ограничение сферы действия эффектов поведения
Вообще говоря, на практике не рекомендуется без разбора пользовать-
пользоваться побочными эффектами. Желательно свести все побочные эффекты в
правила общего назначения, а в частях программы, ориентированных на
конкретные приложения, по возможности не пользоваться побочными
эффектами. Фразы, являющиеся чисто декларативными (т.е. свободные
от побочных эффектов), легче читать и сопровождать. Части программы,
ориентированные на конкретные приложения, будут, по всей вероятности,
использоваться чаще, чем остальные разделы программы. Следовательно,
чем ближе будут специализированные разделы программы к чисто декла-
декларативным, тем лучше.
Программы "место", "изменить терминал" (см. разд. 3.7) и другие
подобные им программы являются в этом отношении плохими примера-
примерами. Эти процедуры ориентированы на решение конкретных задач, но их
работа зависит от предикатов с побочными эффектами поведения.
4.3. БЙХЕВЙОРИСТИЧЕСКИЙ ПОДХОД 201
Программа "найти_или_спросить" '
При прогр; ммиров.. -j/i-iflVi), во-домсак<т сн'уадии, в которых
требуется обеа ичи!< ^лос п^зеде,:. <> лирамми, какого нельзя до-
добиться при простых ."-.aupocax к ба^м данных Пролога. В категорию та-
таких программ о.зычно попадают компоненты больших программ, обеспе-
обеспечивающие интерфейс с пользователем, гак как вряд ли следует ожидать,
чт при применении программы пользователь будет самостоятельно вво-
то1 Пролог-запросы. Другим примером такой ситуации служит поведе-
<¦ программы 'место": когда эта программа не может найти ответ в базе
ых адрес", она спрашивает ответ у пользователя, а затем добавляет
че! ый ответ в базу данных.
1мея в виду изложенное выше, предположим, что мы составляем
едуру общего назначения, в которой применяется такой же подход
к работе с неизвестной информацией, как и в программе "место". Новая
процедура носит название "найти илиспросить", так как если она не
сможет найти нужные сведения в базе данных, то попросит пользователя
предосавить jth сведения. Программа "найтиили спросить" будет ра-
работать только с такими отношениями и атрибутами, сведения о ко-
которых разрешено запрашивать в соответствии с фразой "можно _ за-
запрашивать".
Аргументом процедуры "найтиилиспросить" является запрос.
Процедура пытается выполнить этот запрос. Если запрос будет успешным,
то процедура "найти_или_спросить" просто выдаст результат. Если же зап-
запрос потерпит неудачу, то процедура проверит по специальной базе данных
"можно_запрашивать", можно ли задавать пользователю вопрос об ответе.
Если предикат содержится в базе данных "можно_запрашивать", то про-
процедура "найти_или_спросить" попросит пользователя ввести отсутствую-
отсутствующую информацию, добавит ранее введенный запрос как факт в текущую
программу и выдаст значение, введенное пользователем. Если предикат не
попадает в категорию "можно—запрашивать", то запрос к "найти_или_
спросить" терпит неудачу.
> \ .»* * i^* - -*
найти_или_спроситьCапрос) :- , ,,, , ,,,,"•„
Запрос. ,- „ , ,
кайти или спросить(Запрос) :— ' .•*•'-»* ,->
можно запрашивать (Запрос, Подсказке, Згочение),
var (Значение),
write (Запрос), nl,
1 write (Подсказка), write (' '),
< read (Значение),
assert (Запрос). '
202 'ч ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
% Факт
^ можно_запрашивать(путешествие(А, Б, Видтрансп), ',
% Подсказка Переменная '¦
'введите вид транспорта:', Видтрансп) :- u JU
nonvar(A), nonvar(B). -j ¦¦--
путешествие(манхэттен, куинс, жел_ дорога).
Программой "найтиили спросить" можно воспользоваться «лелеющим
образом: 1
! ?-найти или_спросить(путешествие(манхэттен, куинс, Т)). %1
Т = жел дорога
, ', ?- найти_или_спросить(путешествие(манхэттен, бруклин, Т)). %2
л путешествие(манхэттен, бруклин, _0)
а введите вид транспорта: метро ¦ . - . ¦
w T = метро
1 ! ?- найти или_ спросить (путешествие (манхэттен, бруклин, Т)). % 3
Т = метро
i
Запрос B) показывает, как ведет себя программа "найти_или_спро-
сить", если попросить ее выдать сведения о виде транспорта, которым мож-
можно добраться из одного неизвестного программе пункта в другой. Заметь-
Заметьте, что при выполнении запроса C) факт «путешествие (манхэттен, брук-
бруклин, метро)» уже содержится в программе, и поэтому процедура ни о
чем не спрашивает пользователя.
Оценка бихевиористического подхода
Одна из проблем, возникающих при проведении в жизнь бихевио-
бихевиористического подхода к программированию, заключается в том, что текст
программы при этом получается сложным и не подчиненным "дисципли-
"дисциплине" программирования. При таком подходе можно написать программу,
которую будет столь же трудно понять, как и худшие в этом отношении
программы, написанные на процедурных языках. Именно это произойдет,
если без разбора пользоваться предикатами, обладающими побочными
эффектами поведения. Реляционный подход и подход к программирова-
программированию с позиций потока данных обладают большей "дисциплиной", что опре-
определяет более стройный стиль мышления программиста и в значительной
степени защищает программу от появления запутанных конструкций.
Следовательно, рекомендуется прибегать к бихевиористическому подходу
только в тех случаях, когда два других подхода к программированию
оказываются совершенно неадекватными. Если Вам все же придется вос-
воспользоваться бихевиористическим подходом, то попытайтесь ограничить
сферы действия побочных эффектов, сводя их в процедуры общего назна-
УПРАЖНЕНИЯ п лМмАЧ.Т(ИММ*^ОЧП Ч ИГО^ГГ' ' Г" ' - 203
чения по типу процедуры "найти илиспросить", и не включайте их во
фразы, выполняющие специфические действия по решению конкретных
задач.
И последнее предостережение: на программу, в которой широко ис-
используются побочные эффекты поведения, будут в большей степени оказы-
оказывать влияние различия между версиями языка Пролог, и, следовательно,
такую прохрамму будет труднее переносить с одной версии Пролога на
ДРУГУЮ. Vr ,iM|,: , .,
. БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ
Метод управления поиском при помощи списка посещенных уэлов
(как это делается в программе "тснрпутешествоватьЗ") подробно ис-
исследуется в книге [79].
Идея создания процедуры "найти_или_спросить", приведенной в
данной главе, возникла у автора после знакомства со средством опро-
опросить пользователя языка APES [38]. ^^ ,.
(А (*¦!¦?"*, «,
УПРАЖНЕНИЯ «in,
1. Предположим, что факты базы данных "путешествие" (см. разд. 4.1)
содержат еще по одному аргументу, который задает расстояние в милях
между двумя городами. Напишите программу, которая вычисляет наи-
наиболее короткий путь между двумя городами, при этом за основу возь-
возьмите текст процедуры "тснр_путешествоватьЗ".
Существуют два подхода к решению этой задачи. Один подход осно-
основывается на рекурсии, а второй — на поиске с возвратом.
Рекурсивное решение
При рекурсивном подходе применение предиката "findall" позволя-
позволяет собрать в одном списке все ответы на запрос к программе "тснр_путе-
шествоватьЗ". Далее ответы сортируются, чтобы найти самый короткий
маршрут Во многих версиях языка Пролог имеется встроенный преди-
предикат "keysort" ("сортировка по ключу"), первым аргументом которого
является список структур "-/2", а вторым (выходным) аргументом
служит вырабатываемый данным предикатом список структур "- /2",
отсорированных по значениям первого аргумента. Символ "—" является
обозначением инфиксной операции. Приведем пример запроса.к предика-
предикату "keysort":
! ?— keysort ([6-привет, 3-м(нью_йорк, самолет, лос анжелес),
2-[один]] ,Х).
X = [2-[один],3-м(ньюйорк, самолет,лос анжелес), .„,„...,„ ,
6-привет] < V* х'
204 ГЛ. 4. ПОДХОДЫ К ПРОГРАММИРОВАНИЮ НА ЯЗЫКЕ ПРОЛОГ
Для того, чтобы воспользоваться предикатом "keysort", необходимо так
изменить процедуру "тснрпутешествоватьЗ", чтобы она через четвертый
аргумент возвращала структуру "-/2". Первым аргументом этой
структуры будет расстояние в милях, а вторым - структура "м", описы-
описывающая путь между двумя городами. Предположим, что автомобильный
маршрут между Ньюарком и Бронксом имеет длину в 25 миль, а автобус-
автобусный маршрут между Бронксом и Куинсом - 10 миль. Тогда при запросе
к процедуре "тснрпутешествоватьЗ" должен выдаваться такой ответ:
! ?— тснр_путешествоватьЗ(ньюарк, куинс, М).
М = 35-м (автомобиль, бронкс, м (автобус, куинс) ) .
После проведения сортировки списка ответов на запрос к процедуре
"тснр путешествоватьЗ" ответ, располагающийся в начале списка, будет
соответствовать наикратчайшему пути.
Решение при использовании поиска с возвратом
При реализации поиска с возвратом в процедуру "тснр путешество
ватьЗ" следует добавить дополнительный аргумент, содержащий сведения
о расстоянии (в милях) для определенного машрута между двумя города-
городами. Нужно написать промежуточную процедуру, которую можно, скажем,
назвать "наилучший маршрут". У этой процедуры будут те же аргументы,
что и у процедуры "тснр_путешествоватьЗ". Процедура "наилучший_марш-
"наилучший_маршрут" будет вызывать процедуру "тснр_путешествоватьЗ" как одну из
своих подцелей. В процедуру "наилучший_маршрут" необходимо ввести
глобальную переменную-факт, которую можно, например, назвать "оп-
"оптимум/2". Употребление этой переменной будет во многом похоже на ис-
использование факта "текущсумма" в программе "итогокл" из разд. 3.11.
Первым аргументом факта "оптимум" является структура "м", описываю-
описывающая маршрут между двумя городами, а вторым аргументом — количество
миль для этого маршрута. Первое, что должна сделать процедура "наи-
лучшиймаршрут", — это добавить факт "оптимум", содержащий аргу-
аргумент с очень большим расстоянием, превышающим возможный предел
расстояний для данной задачи, например:
оптимум (, 100000).
Затем процедура "наилучшиймаршрут" должна выдать запрос к процеду-
процедуре "тснрпутешествоватьЗ" и сравнить полученное в результате выполне-
выполнения этого запроса количество миль со значением расстояния, которое со-
содержится в факте "оптимум". Если количество миль, полученное в ре-
результате запроса, будет меньше, чем это расстояние, то процедура должна
удалить факт "оптимум" и добавить вместо него новый факт, в котором
будут содержаться сведения о расстоянии и о новом маршруте, получен-
полученные в результате запроса. Процедура "наилучшиймаршрут" должна про-
УПРАЖНЕНИЯ 205
вести такой поиск с возвратом по всем ответам на запрос к "тснрнуте-
шествоватьЗ". Тогда после исчерпания множества ответов самым ко-
коротким будет маршрут, описываемый текущим фактом "оптимум".
Какое из двух решений приведет к созданию более читабельной програм-
программы? При каком алгоритме решения будет достигнута более высокая ско-
скорость выполнения программы? В какой версии программы будут меньше
потребности в памяти? Какой подход к программированию на языке
Пролог (реляционный, с позиций потока данных, бихевиористический)
будет в наибольшей степени соответствовать применяемому методу реше-
решения в каждом случае?'
2. В примере процедуры "найти или спросить" правило "можноза-
прашивать" охватывает тот случай, когда исходный пункт и пункт назначе-
назначения известны по фразе "путешествие", а вид транспорта неизвестен. Мож-
Можно ли добавить другое правило "можнозапрашивать", применимое к слу-
случаю, когда известны пункт назначения и вид транспорта, а исходный пункт
неизвестен?
В представленном виде, процедура "найти_или_спросить" может ра-
работать с одной неизвестной величиной, входящей в запрос. Попробуйте
написать новую версию программы "найтиилиспросить", в которой
допускалась бы обработка более чем одной неизвестной величины в за-
запросе. К примеру, эта программа должна реагировать на запрос к фактам
"путешествие", в которых известен вид транспорта, а исходный и конеч-
конечный пункты неизвестны. Можете ли Вы привести примеры ситуаций, в ко-
которых найдет применение новая версия процедуры "найти_или_спросить"?
Ui&K.f '-•¦¦*¦
) "•
fl H'> » k , ' М-Л i'l* ' a '*'¦
f i «i 4 i i'1'Щ > UI» << V", 1,.
)V f J ») i 'SI M И u «t, t< ) HI" « * ^>l
4 • <( • ii* , t ¦ ТЙ»" ! «г V bff- ЧМ
"'I'
г*, r«r:.,V'.¦•.'!.:•! ?': ^MiKUMHt-Oi^HK".' В»
ГЛАВА 5
ОБРАБОТКА ТЕКСТА
ВВЕДЕНИЕ и и TJKV
Лексический анализ и грамматический разбор
Пролог обладает большими возможностями по сопоставлению объек-
объектов с эталоном (pattern matching), поэтому данный язык программирова-
программирования очень хорошо подходит для обработки текстов. На Прологе можно
с успехом реализовать генераторы отчетов, текстовые редакторы и трансля-
трансляторы с языков. В данной главе довольно подробно рассматриваются про-
программы, предназначенные для обработки текстов. На примере этих про-
программ демонстрируется непосредственное практическое применение язы-
языка Пролог.
Действия, выполняемые программой обработки текстов, можно раз-
разбить на две фазы. В течение первой фазы, называемой лексическим ана-
анализом, входной текст преобразуется из внешней формы в некоторое внут-
внутреннее представление. Во время второй фазы выполняется анализ или тот
или иной вид обработки внутреннего представления текста. Система грам-
грамматического разбора - это процедура, которая распознает синтаксические
структуры высокого уровня (объекты) во внутреннем представлении
текста.
Содержание данной главы
В первых разделах главы представлена реализованная на Прологе про-
процедура лексического анализа и приводятся примеры двух различных
типов процедур грамматического разбора - процедура нисходящего раз-
разбора и процедура восходящего разбора. В этих примерах используется
грамматика, описывающая несложное подмножество английского языка.
Обсуждение вопросов обработки полного естественного языка выходит
за рамки данной книги. Однако приводимые здесь примеры простых систем
грамматического разбора в определенной степени иллюстрируют проб-
проблемы, возникающие при создании любых систем обработки естествен-
естественного языка.
В конце главы рассматриваются два примера применения систем грам-
грамматического разбора. В первом из них описывается конвертирование Про-
Пролог-программ с вергии языка для ЭВМ DEC-10 на "ядро" микро-Пролога.
5.1. ЛЕКСИЧЕСКИЙ АНАЛИЗАТОР . - AJ/
Эти две версии Пролога отличаются используемым в них синтаксисом.
Во втором примере обсуждается язык запросов к базе данных. Запросы
пишутся на языке, похожем на английский язык, и преобразуются в Про-
Пролог-запросы.
. ш , Стратегии грамматического разбора
... .< и стратегии решения задач
Одна из причин, по которой системы грамматического разбора вызы-
вызывают столь большой интерес, заключается в существовании близкой ана-
аналогии между стратегиями грамматического разбора и стратегиями реше-
решения задач в целом. В интерпретаторе языка Пролог но умолчанию принята
стратегия решения задач с обратным ходом решения. Решение начинается
с гипотезы (т.е. с запроса), которая затем разбивается на субгипотезы
(т.е. подцели правила), далее каждая субгипотеза делится на еще более
мелкие составные части и т.д. Исходная гипотеза будет подтверждена,
когда интерпретатор дойдет до субгипотез, которые уже нельзя разде-
разделить на отставные части (т.е. до фактов). Альтернативой служит страте-
стратегия решения задач с прямым ходом решения. Такая стратегия применяет-
применяется в языке OPS-5. Решение начинается с фактов, а затем отыскиваются
заключения, вытекающие из них. Далее на основании этих заключений
делаются заключения более высокого уровня и т.д. Это происходит до
тех пор, пока не будет достигнуто искомое заключение.
Система нисходящего грамматического разбора базируется (как
и Пролог) на стратегии с обратным ходом решения, а система восходяще-
восходящего раэбора - на стратегии с прямым ходом решения (как и язык OPS-5),
Вообще говоря, нисходящий грамматический разбор более эффективен,
чем восходящий, но существуют некоторые грамматические конструкции,
разбор которых можно реализовать только восходящим методом. По-
Поскольку сам Пролог основывается иа стратегии с обратным ходом решения,
реализация на Прологе систем нисходящего грамматического разбора
может быть осуществлена достаточно прямолинейным способом. Реализа-
Реализация восходящего грамматического разбора немного сложнее, так как для
применения стратегии с прямым ходом решения требуется процедурная
трактовка языка Пролог. Существует также ряд других задач, для кото-
которых более предпочтительно использование стратегии с прямым ходом
решения.
5.1. ЛЕКСИЧЕСКИЙ АНАЛИЗАТОР
Лексический анализатор распознает сочетания символов, поступаю-
поступающих из входного потока, и вырабатывает поток лексем. Каждая лексема
представляет одну из строк символов. Множество лексем, сгенерирован-
ЯЛ•' v ГЛ. 5. ОБРАБОТКА ТЕКСТА
сщп щ KSTojyt^fioit^jr а
Лексический
анализатор
опт т
01 s»qe*«»i
.-.if f,yH,:'
»
Рис. 5.1
ных лексическим анализатором, образует внутреннее представление вход-
входного потока (рис. 5.1).
Процедура "читатьпредлож"
Описываемый здесь лексический анализатор "читатьпредлож" разра
ботан на основе программы, приведенной в книге [22, с. 104] (программа
использована с разрешения авторов). Анализатор "читатьпрепдож" распоз-
распознает слова и знаки препинания, поступающие во входном потоке. Лекси-
Лексический анализатор выбирает из входного потока предложение и возвраща-
возвращает список слов, содержащихся в нем. Слово определяется как множество
букв, на границах которого стоят пробелы или иные недопустимые сим-
символы. Знаки препинания, скажем, запятая и точка, трактуются как само-
самостоятельные слова. Предложение определяется как последовательность
слов, границу которой задают точка, вопросительный или восклицатель-
восклицательный знак. Символ перехода к новой строке рассматривается как пробел,
поэтому предложение может занимать более одной строки.
В программе "читатьпредлож" используются два встроенных пре-
предиката — "getO", считывающий по одному коду символа из текущего
входного потока, и "name", который преобразует список кодов символов
в атом. Ниже располагается текст программы "читатьпредлож".
% имена переменных: '" ""
% Lw = список слов ;
% W, W1 = одно слово ^ , ',*,,<.
% Lc = список символов *
% С, Cl = одиночные символы ,
(t
читатьпредлож ([W i Lw]) : - % считать.рдол|<щВШЦ . , , ,
getO(C),
читатьслово (C, W, Cl), ... , ' ,, .
остатокпредлож^,Cl, Lw),!. _ ..* ' '
' % предыдущее слово и следующий символ введены; счвиать
?Р % оставшуюся часть предложения. ' 'v.
остатокпредлож(\У, —, [ ]) : -
; границапредл (W),!. % конец, если предыдущим словом
15 * % была граница предложения.
f '. ¦¦¦¦¦¦¦
S.I. ЛЕКСИЧЕСКИЙ АНАЛИЗАТОР »., Чн: .tt* лг. • 2W"
ocтaтoкпpeдлoж(W>C, [Wl \ Lw]) : -
читатьслово (С, Wl, Cl),
остатокпредлож(\У1,С1, Lw). ''-w ''f*.1"". ' u :
| ! ') V
7о взять начальный символ, прочитатьиШ9*а«ЖШИКПВк, ryA(»w«
7о следующий символ. f •*•'<< ,j, • v ,fr
читатьслово (С. W, Cl ) : -
пунктуация (С),
name(W, [С]),%по
читатьслово (С, W, Cl) : - ¦"• ->»р
допустимыйсимвол (С),
¦\ " '
getO(C2), ' "•* г
остатокслова(С2, Lc, Cl), % считать сле
% символы.
name(W, [C|Lc]). % построить слово. "' и "
читатьслово (С, W, С1) : - " '1Г1
getO(C2) , % символ С недопустим, ввести новый ' ' '
% символ.
читатьслово (С2, W, C1). % и попытаться повторить.
i расширять слово до тех пор, пока не встретится недопустимый
i СИМВОЛ.
. + -
остатокслова(С, [С \ Lc], Cl) : - % объединить символы
% в список
допустимыйсимвол(С), „, *»«
! , vf и* v '
getO(C2), ;¦;; .4 • ..:
остатокслова(С2, Lc, Cl). \,\
остатокслова (С, [ ], С) . % конец слова если С - Нед»-
% пустимый символ.
% символы, считающиеся самостоятельными словами
пунктуацияD4). % ,
пунктуацияE9). % ;
пунктуацияE8). % :
пунктуация(бЗ). % ? ; -
пунктуация(ЗЗ)..,, % ! ,.,,ЧЛ1,» ,vti,.. «
пунктуацияD6). % .
% диапазоны кодов допустимых символов: н »*,«нч
допустимыйсимвол (I) : - I > 96,1 < 123. % a-z
допустимыйсимвол (I) : - I > 64, К 91. % A-Z |Ч ""•" l!
допустимыйсимвол (I) : - I > 47,1 < 58. % 0-9 гП 5' * "•
% знаки пунктуации, заканчивающие предложение: % ,s (J
границапредл ('.'). .(')>••. .» "
границапредл(' ! ).
границапредл('?'). v^.-f. ifr«SiT5oK ; Л i')' . ^/5"'
Алгоритм работы лексического анализатора "читатьпредлож"
Алгоритм работы программы "читатьпредлож" основан на схеме с
просмотром на один символ вперед. Программа "читатьпредлож" начи-
начинает работу со считывания одного символ'а (С)из входного потока. За-
Затем она передает этот символ процедуре "читатьслово". Процедура "чи-
татьслово" проверяет, не является ли введенный символ (С) знаком пунк-
пунктуации. Если является, то процедура "читатьслово" обращается к встроен-
встроенному предикату "name", чтобы преобразовать этот символ в слово (W),
а затем считывает из входного потока следующий символ (С1). Процедура
"читатьслово" возвращает слово (W) через второй аргумент и новый
символ (С1) - через третий аргумент. Если первоначально считанный
символ (С) не является знаком пунктуации, то следующая фраза про-
процедуры "читатьслово" проверяет, допустим ли этот символ (т.е. он должен
быть символом a-z, A-Z или 0-9). Если символ окажется допустимым,
то процедура "читатьслово" вызовет процедуру "остатокслова" для получе-
получения списка оставшихся символов этого слова (Lc), а затем обратится к
встроенному предикату "name" для превращения списка ([C|Lc]) в
слово (W). Но если исходный символ (С) окажется недопустимым, то
управление будет передано третьей фразе процедуры "читатьслово".
Эта фраза игнорирует недопустимый символ (С), вводит новый символ
(С2) и повторно вызывает процедуру "читатьслово" с новым символом в
качестве ее первого аргумента.
Остальные процедуры — "остатокслова" и "остатокпредлож" - ана-
аналогичны процедуре "читатьслово". Первая фраза процедуры "остатокпред-
"остатокпредлож" проверяет, не является ли последнее обнаруженное слово признаком
границы предложения. Если является, то процедура "остатокпредлож"
проходит через предикат "сократить" и оказывается успешной, что при-
приводит и к успеху процедуры "читатьпредлож".
Использование программы "читатьпредлож"
Программу "читатьпредлож" можно использовать в запросе, например:
! ?— write ('введите предложение'), nl, читатьпредлож(X).
5.2. СИСТЕМА НИСХОДЯЩЕГО ГРАМЩу1Щ$ф}Щ?фЩр#0и Щ
введите предложение w*ro^*> пЖ».. *¦>»«•;• ,;<>«.
d h
The cow jumped over the ггшоп. ; „
A = [ 'The', cow, jumped, over, the moon, ' .'-\
В приведенной версии программы прочие символы (р и т.д.) просто игно-
игнорируются*) . Это видно из следующего примера:
! ?— write ('введите номер по соцстраху и точку: '), читатьпредлож(Х).
введите номер по соцстраху и точку: 12345678.
Х=[123','45\'678','.']
Как можно было бы изменить программу "читатьпредлож", чтобы
эти символы либо стали допустимыми в составе слов, либо считались
бы знаками пунктуации?
5.2. СИСТЕМА НИСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА
Программа "объект"
Система грамматического разбора - это программа, коюрая распозна-
распознает синтаксические объекты в потоке лексем. Здесь описана программа
нисходящего грамматического разбора, названная "объект". На вход
программы поступают список слов и название определенного синтакси-
синтаксического объекта более высокого уровня. Программа разбора добьется
успеха, если в начале списка обнаружит слова, из которых формируется
требуемый синтаксический объект. В противном случае программа потер-
потерпит неудачу. Грамматика для программы "объект" - это несложное под-
подмножество английского языка. Распознаваемые программой синтакси-
синтаксические объекты - это все части предложений английского языка, такие
как "предложение", "глагольная группа" или "артикль".
Программа "объект" одновременно представляет собой
и словарь, и грамматику
Согласно терминологии грамматического разбора терминальный сим-
символ (или терминал) - это входная лексема, а нетерминальный символ
(или нетерминал) — это синтаксический объект, образованный комбина-
комбинацией терминальных или нетерминальных символов. Множество термина-
терминалов, известное системе разбора, называется ее словарем. Компоненты
каждого нетерминала специфицируются при помощи грамматического
правила, а множество грамматических правил, известных системе разбора,
образует ее грамматику.
*) Поэтому для анализа русских предложений необходимо описать в программе
и русские буквы. - Примеч. пер.
212 ;Й1..1*:а*-1>'1»>»:Ж»:т»1,-МЛЧЧ гд s ОБРАБОТКА ТЕКСТА
В описываемой системе используется простая грамматика, которую
можно в схематической форме представить так:
предложение -+ группа_существительного глагольная_группа
группасуществительного -+ артикль существительное
глагольная_группа -+ глагол группасуществительного
Стрелка здесь читается как "состоит из". В программе каждый терминал,
входящий в состав словаря, представляется фактом "объект", а каждый
нетерминал, входящий в грамматику, представляется правилом "объект".
,4tH% имена переменных: ,»>,•.*-..« ,аП.>/и, ж./л/ ,,-(, ¦.
,,,Н1 % I = входной список лексем что/м, к х\- ¦<•*. , ¦¦ ¦.•-¦•
%, О, R = выходной список лексем ¦ •' ^; «• '#,'..> ^ «>
% нетерминалы:
% Вход Выход HajBaHHe r fa? , , >'-:\ '.'-,
объекгA, О, предложение) : -
1 объект (I, R, группасуществительного), •" ' " ' '
.<; объект(R,О, глагольная_группа).. , , '
,г„ рбъектA,0, группа_ существительного) : — , . ,
объект (I, R, артикль),
объект (R, О, существительное).
объект(I, О, глагольная_группа) : — ,<
i объект (I, R, глагол), ,¦¦
oбъeкт(R,O, группасуществительного). ,
% терминалы: к ' '
% Вход Выход Название "¦' | |'
объект ([the! R], R, артикль).'1 n'
.;, объект([cow ! R], R, существительное). "*
, объект( [tail! R], R, существительное). . ^
, объект( [shakes ! R], R, глагол).
объект([walks ! R], R, глагол).
Заметьте,что форма нетерминальных правил "оЦикт" а ДОкммМ оайтвет-
ствует форме грамматических правил. ,ч ^', >. <л>л
Использование программы "объект"
Первым аргументом процедуры "объект" является входной список
лексем. Третий аргумент - это название определяемого объекта. Второй
аргумент образован частью списка, остающейся после того, как из начала
списка будет взят терминал или нетерминал. Функции аргументов можно
проиллюстрировать на примере запроса:
| ?—объект( [cow, horse, goat], Остаток, существительное).
Остаток = [horse, goat]
5.2. СИСТЕМА НИСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА 213
Запрос спрашивает: можно ли взять существительное из начала списка
(([cow, horse, goat])) и если'да, то какая часть списка останется'! Ответ
на данный запрос показывает, что это возможно, и что остается список
«[horse, goat]». Запрос подтверждает, что слово cow является сущест-
существительным.
i Сходным образом, запрос к процедуре "объект" подтвердит или опро-
опровергнет предположение о том, что список слов образует нетерминал:
! ?- объект ((the, cow,'.' ], L, глагольная_группа).
нет , : :
\ ?— объект ([the, cow,' .' ], L, группасуществительного).
L =['.'] % успех
! ?-объект([ the, cow, shakes, the, tail],
"Л ¦ L, предложение). y, i'n;>w ¦ ¦ 'ir ' . s
in L = [ ] %ycnex ¦,. ¦jy;j^'.ri.,. •',„! .
lf Использование процедуры "объект" в обратном направлении
\ Все аргументы процедуры "объект" являются двунаправленными. Это
означает, что при помощи запросов к процедуре "объект" можно также
сгенерировать любые синтаксические объекты, какие только можно по-
построить по входному списку лексем, или даже сгенерировать ва; возмож-
возможные предложения по заданным словарю и грамматике.
% проанализировать входной список: fi s «'¦
! ?- объект ([the, tail], L, Объект). - ';'' % A) ' f':
L= [tail] IV^-.i Г-П-;,-;.;, v ¦ .;!.. "
Объект = артикль ; N!a;' J'tnv'»;.*: ¦:>>« •>•¦ . • * -<,н-(
Объект = группа существительного ; ^¦«¦¦sn кг'п!1 «^itw "'?
% сгенерировать все предложения:
! ?—объект(Х, [ ], предложение). ".'¦'-.< =.м.-.. -^ ¦ ^
X = [the, cow, shakes, the, cow] ; ' <""M' "'st;'J """*'• i;Tmv'".
ЛГ = [г/ге, cow, shakes, the, tail] ; c; ,,,;i,
A" = [г/ге, cow, walks, the, ее л>] ;
¦.I X = [the, cow, walks, the, t il] ; ., ..«i •.»:•.;. ,i;,-q-1* t >./<.. '¦' '-¦ :-»k'F
^. X= [the, tail, shakes, the, cow] \ -" ' ' ' .• ' ';,-;:г. ; r ^;H
i,' ЛГ= [the, tail, shakes, the, tail] ; ' ',". , ,' , .,, .,',¦'. J•,',-.. , ,,,. ,
X = [the, tail, walks, the, cow] ; . . , s ^.»fh;-.¦¦•-. ;;
X = [the, tail, walks, the, tail] ; r' ''" ' ' ' • "T. •'^
214 ГЛ. 5. ОБРАБОТКА ТЕКСТА
Обратите внимание, что в запросе B) второй аргумент [ ] указывает,
что после окончания грамматического разбора должен остаться пустой
список.
Предложения, сгенерированные программой разбора, синтаксически
правильны, однако их семантическая корректность не гарантируется.
Программа может вырабатывать бессмысленные предложения вроде
« [the, cow, walks, the, tail] » (что можно перевести как "Корова идет
по хвосту"). ,,..,,„
Что Вы ожидаете получить от запроса: , ¦ **' "'/<»' '' >т '.';¦.;
I ?-объект (А, В, С). ? •
'¦'"-¦'' i .- \
Расширение грамматики ' '
Грамматику можно расширить многими способами. В частности, можно
изменить определение группы существительного так, чтобы оно позволило
размещать любое количество прилагательных между артиклем и сущест-
существительным. Если в словарь системы добавить прилагательные, скажем,
« big » и « strong », то расширенная версия программы "объект" сможет
проводить грамматический разбор групп существительного типа «the big
strong cow » (большая сильная корова).
Если один и тот же нетерминал будет определяться более чем одним
грамматическим правилом, то система разбора будет действовать точно
так же, как и интерпретатор языка Пролог: вначале она попытается выпол-
выполнить грамматический разбор входного списка в соответствии с первым
правилом; если ее постигнет неудача, то она перейдет к следующему пра-
правилу и т.д. Можно допустить наличие прилагательных в группе существи-
существительного, если определить одно правило для случая, когда прилагатель-
прилагательные отсутствуют, другое правило — когда в группу существительного
входит одно прилагательное, еще одно правило — для случая, когда имеют-
имеются два притягательных и т.д:
группа_ существительного ->¦ артикль существительное
группа_ существительного -»¦ артикль прилагательное существительное
группа существительного -»¦ артикль прилагательное
прилагательное существительное -'
¦-- •/
Такой подход нерационален. Более выгодной стратегией будет опреде-
определение промежуточного объекта, названного "прил", таким образом, чтобы
он мог представлять любое количество прилагательных. Объект "прил"
можно определить при помощи двух правил. Первое правило берет одно
прилагательное из начала входного списка, а затем рекурсивно вызывает
"прил" для поиска прилагательных в оставшейся части списка. Второе пра-
5.2. СИСТЕМА НИСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА _ 215
вило не берет из списка ни одного слова, устанавливая т*М самым, что
"прил" может не иметь в своем составе ни одного слова.
прил ->¦ прилагательное прил ч A)
прил -»• B)
Данное определение "прил" является праворекурсивным, так как в первом
правиле рекурсивный вызов "прил" осуществляется из компоненты пра-
правила, расположенной в крайней правой позиции. Второе правило "прил"
представляет собой пустую продукцию, так как оно не имеет компонент.
Теперь можно определить новую версию группы существительного,
в которой используется "прил":
группасуществительного -»¦ артикль прил существительное
Реализация расширенной грамматики .¦*:•¦
Расширенная грамматика реализована процедурой "о5ьект2":
% нетерминалы: ,-, , ,,,, . •
объект2 (I, О, предложение) :— . .¦
обьект2A, R, группа_ существитепьного)'. .
o6beKr2(R, О, глагольная_группа). : • •> •¦
объект?(Т, О, глагольн*» ipynna) : —
обьект2A, R, глагол), ,,
объект2^, О, группа существительного). '¦¦•'¦
объект2A, О, группасуществительного) :-
объект2 A, R, артикль), . ¦ .
o6beKT2(R, R1, прил),
' объект2 (R1,0, существительное). .,,:.•,.«,, .,.. ¦ ,.
сбъе!<т2A, О, прил) :- .v
объект2 (I, R, прилагательное), ...... '
o6beKT2(R, О, прил). > -,',,'\
объект2A,1, прил). ._;:".
% терминалы:
объект2 ( [big \ R], R, прилагательное).
объект2( [strong ; R], R, прилагательное).
объект2( [brown ! R), R, прилагательное). '¦
объект2 ([the I R], R, артикль).
оь'ъект2 ([cow ', R], R, существительное).
объект2([tail! R], R, существительное).
объект2 ([shakes ] R], R, глагол).
объект2 ([walks | R], R, глагол).
Обратите внимание, что вторая фраза "прил" всегда будет успешной, так
216
ГЛ. 5. ОБРАБОТКА ТЕКСТА
как она не имеет условий. Эта фраза скопирует во второй аргумент любой
список задан«'лй в качестве первого аргумента.
I.t. 4. _. v"i4. ...'' . ч. "I ь;/!Г-jw»'i' грамматический разбор ред-
;.w^fciii.A. .¦ /-i-. . .i ус *!,./.". г ... суи'сствитея'чог'-. с лтеым
ЧИСЛОМ
| ?— объект2([the, big, strong, brown, cow, shakes, the, big, tail], L, ¦;
предложение). . . <
'." L41 .;/:,;;,. ¦'¦¦ :, :
Что Вы ожидаете получить от запроса:
I ?—объект2(Х, [], предложение). ?
Если бы процедура "объект" предназначалась для выдачи корректных
предложений, то как с этих позиций Вы оценили бы поведение последнего
запроса? Приемлемо ли оно? Как можно было бы модифицировать прог-
программу, чтобы она более правильно генерировала предложения?
Принцип работы системы нисходящего грамматического разбора -
Система нисходящего грамматического разбора, такая как "объект"
или "объект2", начинает работу с принятия некоторой гипотезы, а затем
проверяет верность следствий этой гипотезы по данным, содержащимся
во входном списке. Первоначальной гипотезой может, скажем, служить
предположение о том, что во входном списке можно обнаружить нетерми-
нетерминал "предложение". В соответствии с грамматическим правилом для нетер-
(группа _ существительного)
лагольная_группа J
Г существительное) (глагол jf фуппа существительного)
Рис 5.2
5.3. СИСТЕМА ВОСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА 217
минала "предложение" данная гипотеза разбивается на две субгипотезы —
на предположения о том, что во входном списке содержатся "группа_су-
ществительного" и "глагольная _ группа". Эти две гипотезы, в свою оче-
очередь, разбиваются на субгипотезы более низкого уровня. Процесс разде-
разделения гипотез на субгипотезы продолжится до тех пор, пока система не
встретит терминал. В этом случае она попытается установить факт наличия
терминала в начальной позиции входного списка. Иерархия терминалов
и нетерминалов, подразумеваемая грамматикой процедуры "объект2",
показана на рис. 5.2.
5.3. СИСТЕМА ВОСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА к
Принцип работы системы восходящего грамматического разбора
В системе восходящего грамматического разбора применяется иной
принцип работы, чем в системе нисходящего разбора. Системы восходя-
восходящего грамматического разбора начинают работу с данных и переходят
к простым синтаксическим объектам, а затем и к более сложным синтак-
синтаксическим объектам. В то время как система нисходящего грамматическо-
грамматического разбора управляется в первую очередь гипотезами (т.е. принимаемые
ею решения основываются на текущих гипотезах системы), система вос-
восходящего разбора управляется данными (т.е. ее решения принимаются,
исходя из имеющихся данных).
Существует несколько стратегий восходящего грамматического разбо-
разбора. Здесь рассматривается система восходящего разбора "восх_объект".
Она начинает работу со считывания слова из входного списка. Далее по
словарю выясняется, каким типом терминала является это слово. Затем
система просматривает грамматические правила, определяющие нетерми-
нетерминалы, чтобы определить, начинаются ли какие-либо из этих правил с только
что распознанного терминала.
Предположим, что грамматика процедуры "косх_объект" состоит из
тех же трех правил:
предложение -> группа_существительного глагольная^группа
группа_ существительного -* артикль существительное
глагольная_ группа -* глагол группа_существительного
Сперва система разбора ищет "артикль" в начале входного списка слое
Она отыскивает правило, первой компонентой которого является "ар-
"артикль", и находит "группу_ существительного". Затем система пытается
найти все оставшиеся компоненты "группы_ существительного'. В данном
случае имеется только одна компонента — "существительное". Если систе-
система обнаружит, что следующий терминал во входном списке — это "сущеа
вительное", то она успешно идентифицирует "группу_существительного".
Затем система перейдет к поиску другого объекта, первой компонентой
218 лЧр*о* o-o:^mrt^V^i гл-5- ОБРАБОТКА ТЕКСТА
которого является "группа _ существительного". Однако если следующим
терминалом, который она обнаружит, не будет "существительное", то она
отвергнет гипотезу о том, что слова, расположенные в начале входного
списка, образуют "группу—существительного". Система вернется назад
и приступит к поиску другого грамматического правила, первой компонен-
компонентой которого является "артикль".
Система грамматического разбора продолжит поиск этим способом
нетерминалов все более высокого уровня. Поиск будет длиться до тех пор,
пока система не достигнет некоторого целевого нетерминала (такого как
"предложение"). В этой точке она остановится. Если бы целевой нетерми-
нетерминал отсутствовал, то система разбора действовала бы до бесконечности.
Вид правила "восх_ объект"
Система восходящего разбора реализована в виде одной процедуры,
названной "восх_объект". Одни правила процедуры "восх_объект"
определяют терминалы, а другие — нетерминалы. Правила процедуры
"восх_объект" имеют нижеследующую форму:
% Входной Первая компонента
'Hi % список слов. этого объекта.
¦id % Выходной Название Целевой
,вЬ % список слов. объекта, нетерминал.
восх_объект (Вход, Выход, Первый, Название, Цель) : —
<Й5 % подцели, предназначенные для отыскания других компонент
• н' % этого объекта:
-" восх_объект (_, _, терминал, _, Второй), ¦•. .;¦"*«?№ ;
м- восх_объект(_, _,терминал, _,Третий), '¦ ч °*я-н
•Л*ь _ _ ;h Я?,'';!:,¦
¦:у4 % подцель, предназначенная для отыскания нетерминала, "V '¦"'>' ~(
% первой компонентой которого является данный объект^ '" :,
й восх_объект(_, _, Название, _, Цель). !;¦*'];'
Аргументы правила "восх объект"
Первым (входным) аргументом правила "восх_объект" является
список слов. Второй аргумент — это то, что останется от входного спис-
списка после того, как система грамматического разбора достигнет своей
цели. Третий аргумент — название третьей компоненты нетерминала, опре-
определяемого данным правилом. (Эта компонента должна быть найдена до вы-
вызова правила.) Если правило определяет терминал, то третьим аргумен-
аргументом служит константа « терминал >>. Четвертый аргумент — название объек-
объекта, определяемого данным правилом. Пятый аргумент — целевой нетерми-
нетерминал; когда будет достигнут целевой нетерминал, процедура разбора оста-
остановится .
5.3. СИСТЕМА «ВСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА 219
Разработка правила "восх объект"
К моменту, когда заголовок правила "восх_объект" унифицируется
С запросом, первая компонента объекта, определяемого данным правилом,
уже найдена. Если объект, определяемый правилом, является нетермина-
нетерминалом, то тело правила будет содержать вызовы процедуры "восх_объект"
для отыскания остальных компонент объекта. Последней подцелью каждо-
каждого правила "восх_объект" является восходящая подцель, осуществляющая
поиск другого нетерминала, первой компонентой которого служит объект,
определяемый данным правилом. Таким образом, четвертый аргумент
заголовка правила (Название) становится третьим аргументом восходящей
подцели.
Приведем текст процедуры "восхобъект":,
% условие окончания при достижении цели: ;
восх объект(I, I, Цель, _, Цель) :— !.
% терминалы:
+ - + + Ы-л
восх_ объект ([the | R]. О, терминал, артикль, Цель) :— tif.)
восх_объект (R, О. артикль, _, Цель). -.-твдме.-f i
восхобъект (cow ! R], О, терминал, существительное, Цель) :W;' ааой,
восх_объекг (R, О, существительное, _, Цель). с;сЭ
восх_объект( [tail | R], О, терминал, существительное, Цель) :&ян |)К
восх объект (R, О, существительное, .Цель). :l!4"'aU *m
восх_объект( [shakes! R], О, терминал, глагол, Цель) :- \> о&аю
восх_объект (R, О, глагол, _, Цель). ,,,.J()¦)
восх_объект([walks i R],О,терминал, глагол, Цель) :- к,!л?лйаг;ош
восх_объект (R, О, глагол, _, Цель). •» 1 ¦"- 'O,;i«c
% нетерминалы: опп!" кгпш
% предложение -*• группа_существительного глагольная_группа
% + - + - + Р*ж
восх_объектA,0, группа_существительного, предложение, Цель) :—
\ восх_объект (I, R, терминал, _, глагольная_ группа), ^ф!'
; BOcx_o6beKT(R,О, предложение, _, Цель). 'J9JI
, % группа_ существительного -»¦ артикль существительное
восх_объектA, О, артикль, группа_существит •- чого, Цель) : —
I восх_объект (I, R, терминал, _, существтельное),
восх_объект (R, О, группа_существительного, _, Цель)."';
% глагольная_группа -+ глагол группа_существительного* -.„.")
восх_объектA,0, глагол, глагольная_группа, Цель) :— ,;,- ^,;(
, восх_объектA, R, терминал,, группа_существительногр-)#1 :Г
восх_объект(Я, О, глагольная_группа, _, Цель).
А '•'' Анализ процесса грамматического разбора ''"' '
^ Нижеследующий запрос осуществляет разбор простого предложения:
d ! ?— восх_объект( [the, cow, shakes, the,
g tail], О, терминал, _, предложение).
* 0*[/
jj /йнс читать диаграммы
У Рассмотрим более подробно действия системы грамматического раз-
разбора, предпринимаемые ею при обработке запроса. На рис. 5.3—5.9 пока-
показаны различные стадии грамматического разбора предложения. Каждая
стрелка, направленная вниз, обозначает начало нового процесса разбора,
целью которого является объект, на который указывает стрелка. Напри-
Например, первоначальный запрос запускает процесс грамматического разбора
с целью найти предложение. Это представлено на рисунке в виде стрелки,
направленной вниз и указывающей на прямоугольник со словом "предло-
"предложение". Каждая стрелка, направленная вверх, обозначает действия вос-
восходящей подцели, входящей в состав одного из правил "восх_ объект".
Состояние 1 (рис. 5.3): "предложение" — это цель данного процесса
грамматического разбора. Система разбора берет из входного списка
слово «the» и выясняет, что это слово — "артикль".
Состояние 2 (рис. 5.4): система разбора определяет, что "артикль" -
это первая компонента "группы_существительного", а затем стартует
еще один процесс грамматического разбора для того, чтобы найти во вход-
входном списке "существительное". Этот процесс завершается успешно н дает
слово « cow ».
Состояние 3 (рис. 5.5): система разбора выясняет, что "группа_су-
"группа_существительного" является первой компонентой "предложения", и затем
запускает еще один процесс грамматического разбора для того, чтобы
найти "глагольную_группу".
Состояние 4 (рис. 5.6): система грамматического разбора берет из
входного списка спово «shakes» и выясняет, что это слово -- "глагол".
Состояние 5 (рис. 5.7): система определяет, что "глагол" является
первой компонентой "глагольной_группы", а затем запускает новый про-
процесс грамматического разбора для отыскания "группы_ существитель-
существительного".
Состояние 6 (рис. 5.8): система грамматического разбора берег из
входного списка слово «the», выясняет, что это слово является артиклем,
и определяет, что артикль — это первая компонента группы существи-
существительного.
Состояние 7 (рис. 5.9): система начинает новый процесс грамматичес-
грамматического разбора для обнаружения "существительного". Этот процесс успеш-
успешно заканчивается отысканием слова «tail». Вследствие этого процесс р&ъ
5.3. СИСТЕМА ВОСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЭБОРА
221
артикль
«the»
\
предложение
Рид. 3.3 > у
:.
<>.. .i., .;, I предложение а,.-
гру ппа_ сущее гаи тельного | _^,, t
гр^ппа_суш,ествительмого
существительное
« сою »
Рис. 5.5
222
ГЛ. 5. ОБРАБОТКА TEltef A
С.
группа, существительмого
существительное
« cow »
Рис. 5.8
!. СИСТЕМА ВОСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА
223
Рис. 5.9
бора "группы_существительного" будет успешным, далее процесс разбо-
разбора "глагольной_группы" окажется успешным и, в свою очередь, исходный
процесс грамматического разбора "предложения" также завершится ус-
успешно.
Леворекурсивные правила
В системе грамматического разбора "объект2" определение объекта
"группа_существительного" было модифицировано с тем, чтобы эта груп-
группа могла содержать любое количество прилагательных. Это было достигну-
достигнуто при помощи праворекурсивного определения объекта "прил":
прил -»¦ прилагательное прил
прил -»¦
Такое определение нельзя реализовать в программе "восх_объект", так
как при восходящем грамматическом разборе невозможна обработка пус-
пустых продукций. Но система восходящего разбора может работать с лево-
леворекурсивными грамматическими правилами, которые вызвали бы беско-
бесконечное зацикливание системы нисходящего разбора. Приведем леворе-
леворекурсивное определение объекта "группа_существительного", в котором
допускается наличие любого числа прилагательных:
О)
группа_существительного -»¦ артикль прилсущ
прилсущ -»¦ прил существителъное
прилсущ ->¦ существительное
прил -»¦ прил прилагательное i
прил -»¦ прилагательное >
B)
C)
D)
E)
224 ГЛ. 5. ОБРАБОТКА ТЕКСТА
В этой грамматике дается леворекурсивное определение объекта
"прил", который является одним или более прилагательным (В прави-
правиле D) "прил" располагается перед объектом "прилагательное".) Вводит-
Вводится новый промежуточный объект — "прилсущ", который является либо
только существительным (в соответствии с правилом C)), либо сущест-
существительным, перед которым стоит любое количество прилагательных
(по правилу B)). Правило A) определяет "группу существительного"
как "артикль", за которым следует "прилсущ". Приведенная грамматика
реализуется процедурой "восх_объект2":
% условие окончания при достижении цели:
восх_объект2A,1, Цель, _, Цель) :—! .
% терминалы:
% + - + - t
восх_объект2 ([the | R], О, терминал, артикль, Цель) : —
восх_объект2(R, О, артикль, _, Цель). V
восх_объект2 ([cow | R], О, терминал, существительное, Цель) :-г
восх_объект2 (R, О, существительное, _, Цель).
восх_объект2 ([tail | R], О, терминал, существительное, Цель) : —
восх_объект2 (R, О, существительное, _, Цель).
восх_объект2 ( [big I R], О, терминал, прилагательное, Цель) :-
восх_объект2 (R, О, прилагательное, _, Цель).
восх_объект2 ([strong | R], О, терминал, прилагательное, Цель) :—
восх_объект2 (R, О, прилагательное, _, Цель).
% нетерминалы:
% группа существительного -»¦ артикль прилсущ
восх_объект2 (I, О, артикль, группа существительного, Цель) : —
восх_объект2 (I, R, терминал, _, прилсущ),
восх_объект2 (R, О, группа_существительного, _, Цель).
% прил -»¦ прил прилагательное
восх_объект2A, О, прил, прил, Цель) : —
восх_объе1.т2 (I, R, терминал, _, прилагательное),
восх_объект2 (R, О, прил, _, Цель).
% прил -»¦ прилагательное
восх_объект2(I, О,прилагательное,прил, Цель) :— #;"¦
восх_объект2 (I, О, прил, _, Цель). ж--л*
% прилсущ -»¦ прил существительное ;.-::/,:-•,
восх_объект2 (I, О, прил, прилсущ, Цель) :- , •»-• г
восх_объект2 (I, R, терминал, _, существительное),- ;
восх_объект2^, О, прилсущ, _, Цель).
5.3. СИСТЕМА ВОСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА
225
% прилсущ -*• существительное
восх_объект2 (I, О, существительное, прилсущ, Цель) : —
восх_объект2 (I, О, прилсущ, _, Цель).
Работа леворекурсивного правила
Леворекурсивное правило "прил" работает следующим образом. Когда
процедура грамматического разбора возьмет из входного списка "прила-
"прилагательное", она обнаружит, что "прилагательное" является первой ком-
компонентой "прил". Для каждого дополнительного "прилагательного" из
входного списка процедура разбора будет вновь проходить через правило
"прил". После того, как процедуре разбора больше не удастся обнаружить
"прилагательных" во входном списке, она приступит к поиску другого
правила, первой компонентой которого будет "прил". Процедура найдет
правило "прилсущ". Если во входном списке следующим словом окажет-
окажется "существительное", то она успешно распознает "прилсущ".
Запрос к процедуре "восх_объект2 "
Нижеследующий запрос показывает, что процедура "восх_объект2"
Может выполнить грамматический разбор "группы_ существительного",
содержащей произвольное число прилагательных:
! ?- восх_объект2( [the, big, brown, cow], [], терминал, _,
группа _ существител ьного).
да
Процесс грамматического разбора этого предложения иллюстрируется
рис. 5.10-5.15.
Состояние 1 (рис. 5.10): "группа существительного" является целью
грамматического разбора. Процедура разбора берет слово «the» из входно-
входного списка и выясняет, что это слово — "артикль".
Состояние 2 (рис. 5.11): процедура разбора обнаруживает, что "ар-
"артикль" является первой компонентой "группысуществительного", а за-
группа _ существительного I
— I
артикль
«the»
Рис. 5.10
8. Дж. Малпас
группа_суш,ествительного 1
артикль
«the»
Рис. 5.
прилсуш,
11
226
ГЛ. 5. ОБРАБОТКА ТЕКСТА
ч
Групп а_ существ и тельного
артикль
«the»
лрилсуш,
прил
прилагательное
Рис. 5.12
группа_оуществи тельного
прилагательное
« brown »
Прилагательное
« bigr»
Рис. 5.13
5.3. СИСТЕМА ВОСХОДЯЩЕГО ГРАММАТИЧЕСКОГО РАЗБОРА
227
группа_суш,ествительного
прилагательное
« brown »
прилагательное
« biff»
Рис. 5.14
м начинает новый процесс грамматического разбора для поиска "прил-
щ".
Состояние 3 (рис. 5.12): процедура разбора берет из входного потока^
1рилагательное" и выясняет, что "прилагательное" является первой ком-
компонентой объекта "прил" (в соответствии со вторым правилом "прил").
Состояние 4 (рис. 5.13): процедура разбора обнаруживает, что "прил"
является первой компонентой "прил" (по первому правилу "прил"), а за-
затем запускает новый процесс грамматического разбора, чтобы найти "при-
"прилагательное". Разбор заканчивается успешно и дает слово «brown».
Состояние 5 (рис. 5.14): процедура разбора выясняет, что "прил"
является первой компонентой "прил" (по второму правилу), но больше
не может найти прилагательных во входном потоке. Она возвращается
назад и определяет, что "прил" является также и первым элементом объек-
объекта "прилсущ".
Состояние 6 (рис. 5.15): процедура начинает новый процесс грамма-
грамматического разбора, чтобы найти "существительное". Это приводит к успе-
228
ГЛ. 5. ОБРАБОТКА ТЕКСТА
групп а_существительного
прилагательное
« brown»
прилагательное
« Ь 1д »
Рис. 5.15
ху - она находит слово «cow». Вследствие этого процесс разбора "прил-
, сущ" завершается успешно, что, в свою очередь, приводит к успеху раз-
разбора "группы _существительного".
Как Вы полагаете, каким будет поведение процедуры восходящего
грамматического разбора, если попросить ее сгенерировать предложения
при помощи, например, такого запроса:
| ?- восх_объект2(Х, [ ], терминал, _, предложение). ?
Использование процедур грамматического разбора
Приведенные примеры систем грамматического разбора — процедуры
"объект" и "восх_объект" — могут лишь проверить синтаксис входного
предложения. (Процедура "объект" может также генерировать предложе-
предложения, если только грамматика не содержит рекурсивных правил.) В боль-
большинстве приведенных примеров запросов процедура разбора берет входное
(V
5.4. DEC-ЮНА МИКРО-ПРОЛОГЕ 229
предложение, а затем подтверждает или опровергает предположение о том,
что данное предложение поддается грамматическому разбору. Гораздо
более важной сферой применения систем грамматического разбора являет-
является перевод с одного языка на другой. Этот род задач выполняется компи-
компиляторами, программами обработки языка запросов или программными
системами машинного перевода.
В разд. 5.4 будет представлен простой конвертер, преобразующий
Пролог-программы, написанные с использованием синтаксиса DEC-10
на подмножество микро-Пролога, называемое синтаксическим ядром
микро-Пролога. В отличие от интерфейсной программы для DEC-10, постав-
ремой вместе с микро-Прологом, программа-конвертер из данной книги
эжет работать с входным файлом в пакетном режиме, вырабатывая
входной файл с преобразованной исходной программой. Эта же програм-
а-конвертер может переводить и программы, написанные на подмножест-
микро-Пролога (ядро Пролога), на DEC-10 — версию языка. Программа-
Ьсонвертер будет полезной в тех случаях, когда Вам потребуется перевести
Программу с одного из двух названных диалектов Пролога на второй.
[ В разд. 5.5 будет представлен интерпретатор простого языка запросов,
|соторый транслирует запросы вида
выдать служащий имя и служащий
оклад где отдел является 100.
(Выдать имена и оклады служащих отдела № 100.)
в Пролог-запросы, а затем выполняет эти запросы.
Процедуры нисходящего грамматического разбора, такие, как приве-
приведенная выше процедура "объект", являются основой и программы—кон-
программы—конвертера, и интерпретатора языка запросов. Но конвертер и интерпретатор
языка запросов можно реализовать и при помощи процедуры восходящего
грамматического разбора, такой, как "восх_объект". Здесь применены
процедуры нисходящего грамматического разбора, так как для используе-
используемых типов грамматик они являются более простыми, чем процедуры вос-
восходящего разбора.
5.4. КОНВЕРТЕР ПРОГРАММ С DEC-10 ПРОЛОГА НА МИКРО-ПРОЛОГ
Синтаксис микро-Пролога
Микро-Пролог — это версия языка Пролог, имеющаяся на многих не-
небольших компьютерах. Основу синтаксиса микро-Пролога составляет
так называемое синтаксическое ядро, которое значительно отличается от
употребляемого в настоящей книге синтаксиса DEC-10. Ниже приводится
программа "d_ to_m", преобразующая синтаксис DEC-10 в синтаксис
ядра микро-Пролога и обратно. Автор преследовал несколько целей, вклю-
включая данную программу-конвертер в книгу. Перечислим эти цели:
23Q. ГЛ. 5. ОБРАБОТКА ТЕКСТА
1) данная программа призвана проиллюстрировать то, как можно
воспользоваться одной и той же Пролог-программой для перевода с од-
одного языка на другой и обратно при условии, что оба языка обладают
сходной структурой;
2) программа показывает взаимное соответствие между компонента-
компонентами DEC-10 Пролога и микро-Пролога, что будет полезным для читателей,
интересующихся обоими языками;
3) данная программа-конвертер может быть использована для пере-
перевода программ с одной версии языка Пролог на другую.
Компоненты микро-Пролога
Термы микро-Пролога - это переменные и константы. Структуры
отсутствуют в микро-Прологе. Любое слово, начинающееся с букв X,
Y, Z, х, у, z или с символа _, — это переменная. Наиболее важным синтак-
синтаксическим объектом микро-Пролога является список, который, записывает-
записывается как помещенное в скобки множество термов, отделенных друг от дру-
друга пробелами (а не запятыми). В микро-Прологе имеется такое же обозна-
обозначение конструктора списка (символ |), как и в DEC-10 Прологе (см.
табл. 5.1).
Выражение, представляющее отношение, в микро-Прологе записывает-
записывается как список, первым элементом которого является имя прилагательное,
а остальными элементами — аргументы (см. табл. 5.2).
Таблица 5.1
Таблица 5.2
Списки
DEC-10 микро-Пролог Отношения
DEC-I0 микро-Пролог
[а, Ь, с] (a b с)
[X1 Y ] (X! Y) отец(филип, (отец филип
[один,двг!К] (одиндва;!*) чарльз) чарльз)
Таблица 5.3
Фразы
DEC-I0 микро-Пролог
знает(Х,У):- ((знаетХУ)
работает(Х, Z), (работает X Z)
работает (Y, Z). (работает Y Z))
отец (филип, чарльз). ((отец филип чарльз))
5.4. DEC-10 НА МИКРО-ПРОЛОГЕ 231
Фраза записывается как список выражений, описывающих отношения,
в котором первый элемент — это заголовок фразы, а остальные элементы
составляют тело фразы. Факт — это список, содержащий только одно вы-
выражение, представляющее отношение (см. табл. 5.3).
Должно быть ясно, что структуры обоих вариантов языка Пролог
очень близки. Во многих случаях выражение, написанное на одной из вер-
версий языка, имеет точный аналог в другой версии. Наиболее важные разли-
различия между двумя рассматриваемыми версиями Пролога заключаются
в отличиях встроенных предикатов. Для простоты программа "d_to_m"
не принимает во внимание встроенные предикаты.
Реализация программы "d _ to _ m"
Программа "d_to_m" реализована как процедура нисходящего грам-
грамматического разбора. В отличие от процедуры "объект", процедура
"d_to_m" имеет пять аргументов. Первый аргумент — это название тер-
терминала или нетерминала, определяемого фразой. Если программа перево-
переводит текст с синтаксиса DEC-10 на синтаксис микро-Пролога, то вторым
аргументом служит входной список (выражение на DEC-10 Прологе),
третьим аргументом будет то, что останется от входного списка после
окончания разбора, а четвертым аргументом является выходной список
(выражение на микро-Прологе). Если же программа преобразует текст,
написанный на микро-Прологе, в текст на DEC-10 Прологе, то четвертый
аргумент — это входной список (выражение на микро-Прологе), пятый
аргумент — это то, что останется от входного списка, а второй аргумент
будет содержать выходной список (выражение на DEC-10 Прологе).
% имена переменных:
% Id входное выражение на DEC-10 Прологе
% Im входное выражение на микро-Прологе
% Od, Rd, Rdl выходные выражения на DEC-10 Прологе
% От, Rm, Rm 1 выходные выражения на микро-Прологе
%
% в комментариях представлено:
% нетерминал — > компоненты DEC-10 Пролога//компоненты микро-
% Пролога
% терминалы:
% + ? ? ? ?
d_to_m (атом, [Слово | Od], Od, [Слово | От], От) :-
atom (Слово).
d_to_m (перем, [ДСлово | Od], Od, [МСлово ! От], От) :-
(nonvar (ДСлово), % направление: с DEC на МР
пате (ДСлово, [С j Остаток]),
uppercase (С),
232 ГЛ. 5. ОБРАБОТКА ТЕКСТА
% поместить символ _ в начало ДСлово,чтобы получилась
% переменная микро-Пролога:
name (МСлово, [' _ ', С ] Остаток])
nonvar (МСлово), % направление: с МР на DEC
name (МСлово, [С | Остаток]),
% сделать первую букву прописной, чтобы получилась
% переменная DEC-10 Пролога:
capitalize (С, ПропС),
name (ДСлово, [ПропС ^Остаток])
)'• " ¦ ' •
% список --->[]//()
d_to_m (список, ['[',']'! Od], Od,['('.')' I- От], От).
% нетерминалы:
% список —> [арг ты] // (аргты) ¦ -
d_to_m (список, [' [' | Id], Odf [' (' ! Im], От) :-
d to_m (арг_ты, Id, [']' \ Od], Im, [')' | Om]).
% список —> [арг_ты j перем] // (аргты перем)
dtom (список, [' [' ! Id],Od, ['(' | Im],Om):-
dlto_m (арг_ты, Id, [' !' | Rd], Im, [' \' \ Rm]),
d_to_m (перем, Rd, [']' | Od],Rm,[')' |Om]).
% фраза —> отношение :— отношения . // (отношение отношения)
d_to_m (фраза, Id, Od, ['(' ! Im] ,Om):-
d_to_m (отношение, Id, [':- ' i Rdl], Im, Rml),
d_to_m (отношения, Rdl, [' .'\ Od],Rml, [')' ] Om] ).
% фраза —> отношение . // ( отношение )
d_to_m (фраза, Id, Od, [' (", Im], Om) :-
d_to_m (отношение, Id, ['.' | Od], Im, [')' | Om]).
% отношения —> отношение , отношения // отношение отношения
dtom (отношения, Id, Od, Im, Om) :-
dtom (отношение, Id, [', ' | Rdl], Im, Rml),
d to_m (отношения, Rd 1, Od, Rm 1, Om).
% отношения —> отношение // отношение
d_ to m (отношения, Id, Od, Im, Om) :—
dtom (отношение, Id, Od, Im, Om).
% отношение —> атом (аргты) // (атом аргты )
dtom (отношение, Id, Od, [' (' ! Im], Om) :-
dtom (атом, Id, [' (' ! Rd 1 ], Im, Rm 1),
dtom (арг_ты, Rdl, [')' | Od],Rml, [" |
\A. DEC-10 НА МИКРО-ПРОЛОГЕ 233
% отношение—>атом// (атом)
d_to_m (отношение, Id, Od, [' (' i Iml * Om):-
d_to_m (атом, Id, Od, Im, [')' j Om] ).
%арг_ты —> аргумент, аргты // аргумент арг ты
d torn (арг ты, Id, Od, Im, Om) :-
d_to_m (аргумент, Id, [',' J Rd], Im, Rm),
d_to_m (аргты, Rd, Od, Rm, Om).
% арг_ты —> аргумент // аргумент
d_to_m (арг ты, Id, Od, Im, Om) :-
d_to_m (аргумент, Id, Od, Im, Om).
% аргумент —> перем ; атом ; список
d_to_m (аргумент, Id, Od, Im, Om) :-
d_to_m (перем, Id, Od, Im, Om)
d_to_m (атом, Id, Od, Im, Om)
d_to^ m (список, Id, Od, Im, Om).
Использование процедуры "d_to_m"
Подадим на вход процедуры "d to m" простой факт, записанный
на DEC-10 Прологе, и посмотрим, что получится на выходе процедуры.
Факт:
отец(филип, чарльз).
можно представить в виде списка слов:
[ отец,' (', филгат, чарльз,')','.']
Этот список можно подвергнуть грамматическому разбору:
I ?— d_to_m (фраза,
[ отец,' (', филгат, чарльз, )',' .' ],
П.мр.П).
МР= [ ( , ( , отец, филип, чарльз, ) , ) J
От формы записи в виде списка легко можно перейти к обычной форме
записи факта в микро-Прологе:
( (отец филип чарльз) )
С другой стороны, правило, записанное на микро-Прологе:
( (элемент X (Y | Z)) (элемент XZ))
234 ГЛ. 5. ОБРАБОТКА ТЕКСТА
можно разложить на следующие элементы:
( , ( .элемент,X, ( ,Y, i ,Z, ) ,
) , ( , элемент, X, Z, ) , ) ]
Затем это правило можно подвергнуть грамматическому разбору:
|?- d_to_m (фраза,DEC, [], u'/il[
['('.'С элемент, X,'(',Y, ^"
'\'Л,'У,')','('. элемент,
X.Z,')',')'],
[])•
DEC" [элемент, '(', X,',','[', 'Y',' I',
'Z'.'Y, ')'.':-', элемент, '(',
X,',',Z,')','.']
От формы записи в виде списка можно перейти к следующей форме:
элемент (X, [Y J Z]) :- элемент (X, Z). ' ¦ ¦
Улучшение интерфейса с пользователем
Одно из затруднений, связанных с использованием приведенных выше
запросов, заключается в том, что для этих запросов требуется кропотли-
кропотливый перевод языковых выражений в списки, состоящие из элементов.
Ранее мы уже пользовались программой, которая автоматизировала эту
утомительную задачу. Это был лексический анализатор "читатьпредлож",
описанный в начале главы. Однако для того, чтобы стало возможным
применение процедуры "читатьпредлож" для ввода Пролог-текстов, в
базу данных "пунктуация" необходимо добавить дополнительные лексико-
лексикографические символы, такие как , и ; .
Для преобразования выходных данных систем грамматического
разбора в удобочитаемую форму можно воспользоваться процедурой,
которая выводит на печать каждый элемент списка. Эту функцию вы-
выполняет процедура "печать_выраж":
печать_выраж ([]):— nl.
печать_выраж(Х | Y]) :—
write(X), write (' '), печать_выраж(У).
Теперь можно употребить процедуру "d_to_m" в нижеследующем состав-
составном запросе:
! ?— write ('введите фразу DEC-10Пролога:'),
nl,
читатьпредлож (DEC),
d_to_m (фраза, DEC, [ ], МР, [ ] ),
печатьвыраж (МР),
fail.
5.4. DEC-10 НА МИКРО-ПРОЛОГЕ 235
введите фразу DEC-10Пролога:
отец (филип, чарльз).
((отец филип чарльз) )
нет
Подцель «fail», стоящая в конце запроса, подавляет печать значений
переменных. ''
Ограничения процедуры "d_to_m"
Приведенная версия процедуры "d_to_m" не может обрабатывать
следующие синтаксические особенности DEC-10 Пролога:
1) структуры;
2) префиксные, инфиксные и постфиксные операции:
3) большую часть встроенных предикатов.
Это как раз те особенности, по которым отсутствует структурное сходст-
сходство между рассматриваемыми версиями языка Пролог. Поэтому для рас-
расширения процедуры "d_to_m" с тем, чтобы она смогла работать с этими
языковыми средствами, потребуется добавить правила, которые будут
применяться только при конвертировании в одн^ сторону. Например,
вследствие того, что в микро-Прологе отсутствуют структуры общего
назначения, имеющиеся в DEC-10 Прологе*), программист, пишущий
программы на микро-Прологе, пользуется списками во многих ситуациях,
в которых программист, работающий на DEC-10 Прологе, употребил бы
структуру. Поэтому если бы программа "d_to_m" применялась для кон-
конвертирования с DEC-10 Пролога на микро-Пролог, то она должна была
бы преобразовывать каждую структуру DEC-10 Пролога в список микро-
Пролога. Но в этом случае при переводе программ с микро-Пролога ла
DEC-10 Пролог возникла бы неоднозначность: если программа-конвертер
встретит в микро-прологовском тексте список, то будет неясно во что
его следует преобразовывать — в список DEC-10 Пролога или же в структу-
структуру DEC-10? Если допустить, чтобы правила, устанавливающие взаимное
соответствие между структурой DEC-10 Пролога и списком микро-Проло-
микро-Пролога, были бы полностью двунаправленными, то в программе "d_to_m"
нужно было бы иметь два способа грамматического разбора каждого спис-
списка микро-Пролога.
Наиболее надежное, хотя и требующее кропотливой работы решение
этой задачи состоит в том, что заранее объявлять имена и количества аргу-
аргументов всех структур DEC-10, используемых в программе. Тогда если
при переводе с микро-Пролога на DEC-10 Пролог программа "d_to_m"
встретит список микро-Пролога, то она обратится к базе данных, состоя-
*)В микро-Прологе есть целостные информационные элементы (tuples), но
оии не могут быть вложенными таким же образом, как структуры.
236 ГЛ. 5. ОБРАБОТКА ТЕКСТА
щей из структур DEC-10, чтобы выяснить, во что нужно преобразовать
этот конкретный список — в DEC-10 структуру или же в список DEC-10.
Приведем текст расширения программы "d_to_m", которое реализует на
практике этот метод работы со структурами.
% база данных, состоящая из структур DEC-10:
% Имя Количество аргументов
структура (клиент, 3).
структура (маршрут, 3).
% преобразовать список микро-Пролога в структуру DEC-10:
% структура_или список —> атом ( арг_ты ) // ( атом арг_ты )
dtom (структура_или_список, Id, Od, Im, Om) :-
найти_допустимую_сгруктуру (Id, Od, Im, Om).
% -
найти_допустимую_структуру ([ Имя,' (' | Rd], Od,
% + _ "¦-'¦¦-
['(', Имя | Rm],Om) :-
var(Rd), % направление: с МР на DEC
atom (Имя),
% проверить, является ли переменная Имя именем структуры
%DEC-10:
структура (Имя, Кол_во_арг),
% взять аргты из начала списка Rm:
d_to_m (арг_ты, Rd, [')' | Od], Rm,
[')' jOm]),
% проверить правильность количества аргументов:
length (Rm, Rm длина),
length ( [')' ; Om], От длина),
Колвоарг is Отдлина — Rmflnmm.
% преобразовать структуру DEC-10 в список микро-Пролога:
% структура или_список —>атом ( арг_ты ) // (атомарг_ты)
d_to_m (структура_или_список, [Имя,' (' ] Rd], Od,
['('.Имя i Rm],Om) :-
var (Rm), % направление: с DEC на МР
atom (Имя),
d_to_m (арг_ты, Rd [')' | Od], Rm, [')' | Om] ).
% преобразовать список микро-Пролога в список DEC-10 или
% наоборот:
% структура_или_список —> список // список
d_to_m (структура_или список, Id, Od, Im, Om) :—
not (найти_допустимую_структуру (Id, Od, Im, Om)),
d_to_m (список, Id, Od, Im, Om). i
5.5. ЯЗЫК ЗАПРОСОВ 237
% аргумент—>перем; атом; структура _или список
d_to_m (аргумент, Id, Od, Im, Om) :-
d_to_m (перем, Id, Od, Im, От)
d_to_m (атом, Id, Od, Im, Om)
d_to_m (структура_или_список, Id, Od, Im, Om).
Нижеследующие запросы иллюстрируют работу данного расширения про-
процедуры "d_to_m".
| ?- repeat,
write (' введите структуру или список микро-' ),
write ('Пролога:' ), nl,
читатьпредлож (МР),
owiH_pa3(d_to_m (структураилисписок, DEC, [ ], МР, [ ])),
печать выраж(DEC), nl,
fail.
введите структуру или список микро-Пролога:
(один два три)
[ один, два, три ]
введите структуру или список микро-Пролога:
(клиент смит сокращенная неделя)
клиент(смит, сокращенная, неделя)
введите структуру или список микро-Пролога:
(маршрут нью—йорк бостон)
[ маршрут, нъюйорк, бостон ]
В последнем примере список не был преобразован в структуру "маршрут",
так как согласно объявлению количество аргументов у структуры "марш-
"маршрут" должно равняться трем, а не двум.
t Остальные особенности DEC-10 Пролога, такие как операции и встроен-
Ые предикаты, можно реализовать по аналогии с тем, как это было сдела-
о для структур.
5.5. ЯЗЫК ЗАПРОСОВ
Следующим примером применения системы грамматического разбора
служит программа, которая преобразует предложения англоподобного
языка запросов к базе данных в Пролог-запросы, а затем выполняет запро-
запросы и печатает ответы. Процесс перевода здесь более сложен, чем в програм-
программе '"d_to_m", поскольку два употребляемых языка не являются структур-
структурно сходными.
238 ГЛ. 5. ОБРАБОТКА ТЕКСТА
Спецификация схемы базы данных
Перед тем как станет возможным применение англоподобного языка
запросов к базе данных, в программу нужно ввести явные знания о ко-
количестве и именах аргументов э^ой базы данных. Эта информация позволит
пользователю обращаться к аргументам предикатов tto именам. ПредйЬ-
ложим, что мы будем опрашивать следующие базы данных: кгнэм
служащий (брайен, 100, оператор, 20000). 'мжц'
служащий (нэнси, 200, начальник, 71000). i шнэм
служащий (ральф, 100, менеджер, 71500). ,„ ,
отдел A00, обработкаданных, ральф).
отдел B00, продажа, жб).
Имя опрашиваемой базы данных и имена ее аргумеитов специфицируются
при помощи фактов "схема":
% интерфейс с базами данных "служащий" и "отдел":
% Имя предиката Имена аргументов
схема (служащий, [имя, код, должность, оклад]),
схема (отдел, [код, имя, менеджер]).
Программа также полагается на факты "схема" при определении числа
аргументов каждой базы данных Пролога. Приведенные выше факты
содержат неявную информацию о том, что база данных "служащий" имеет
четыре аргумента, а база данных "отдел" — три аргумента.
После того как в интерпретатор языка запросов будут введены знания
о схемах баз данных "служащий" и "отдел", интерпретатор сможет обраба-
обрабатывать, к примеру, такие запросы:
выдать служащий имя и отдел менеджер
где служащий код является отдел код.
(выдать имя служащего и менеджера отдела, причем код
служащего равен коду отдела.)
В ответ на данный запрос интерпретатор выдаст следующую информацию:*)
служащий имя брайен отдел менеджер ральф
служащий имя нэнси отдел менеджер жб
служащий имя ральф отдел менеджер ральф
¦'Автор пользуется англоподобным языком запросов. При переводе "англо-
подобность" будет проявляться только в том, что сохранится английская структура
запроса на псевдоестественном языке, принятая автором. Слова же, входящие в состав
запроса, здесь даются в русском переводе. Это приводит к построению неудобочитае-
неудобочитаемых "русских" предложений. Если же попытаться русифицировать структуру запроса
(с учетом согласования слов по падежам и т.п.), то зто потребует коренной переделки
5.5. ЯЗЫК ЗАПРОСОВ 239
Стратегия реализации
Действия, выполняемые при помощи описываемого языка запросов,
можно разделить на три этапа. На первом этапе система нисходящего разбо-
разбора преобразует предложение языка запросов в список структур "т" (от сло-
слова "триплет"). Каждая структура "т" содержит имя предиката, имя аргу-
аргумента и неконкретизированную переменную, которая должна нести значе-
значение аргумента. Если предполагается, что два значения эквивалентны (как в
приведенном выше примере запроса код служащего и код отдела), то пере-
переменные из двух структур "т", несущие это значение, унифицируются. На
втором этапе список структур "т" преобразуется в составной запрос Проло-
Пролога. На третьем этапе запрос выполняется и значения переменных выводятся
на печать.
К примеру, на первом этапе приведенный выше запрос подвергается
грамматическому разбору и превращается в нижеследующий список струк-
структур "т":
[т(служащий, имя, N),
т (отдел, менеджер, М),
т (отдел, код, С),
т(служащий, код, С)]
На втором этапе этот список преобразуется в составной запрос:
служащий (N,C, _, _), отдел (С, _, М)
На третьем этапе осуществляется выполнение составного запроса.
Требуемые значения выводятся на печать при помощи процедуры "печа-
тать_тсписок":
! ?- печатать_тсписок ([ т (служащий, имя, брайен),
т (отдел, менеджер, ральф) ]).
служащий имя брайен отдел менеджер ральф
Преимуществом такого подхода является то, что список структур "т"
выступает в роли интерфейса между системой грамматического разбора
языка запросов и остальной частью программы. Если вторая фаза програм-
программы (т.е. часть программы, преобразующая список структур в запрос Проло-
Пролога) работает надежно, то на этапе предварительной обработки может быть
использована любая процедура, вырабатывающая список структур "т".
Программ и существенного их усложнения, что для данной книги неоправданно. При-
Приведенные выше ответы интерпретатора равнозначны следующим ответам:
имя служащего — брайен, менеджер отдела — ральф
имя служащего - нэнси, менеджер отдела - жб
имя служащего - ральф, менеджер отдела - ральф
-Примеч. пер.
240 ГЛ. 5. ОБРАБОТКА ТЕКСТА
Грамматика языка запросов
Грамматика языка запросов полностью приведена в табл. 5.4.
В таком виде данный язык запросов слишком прост для использования
на практике. Единственное отношение, известное в нем, — это равенство
значений атрибутов двух баз данных. Нельзя проверить на равенство значе-
значение атрибута и константу. Было бы целесообразным ввести в язык допол-
дополнительные отношения, скажем, неравно или больше (для числовых значе-
значений). Помимо команды выдать желательно реализовать и другие команды,
к примеру, команды сортировать ^суммировать. Можно расширить описы-
описываемый здесь язык запросов за счет добавления в него этих средств.
Таблица 5.4
Грамматика языка запросов
Нетерминалы:
предложение — > команда пасписок уточнение
па список —> па соединитель пасписок *
пасписок —> па
па — > предикат аргумент
уточнение -> союз па отношение па
уточнение ->
Терминалы:
команда — > "выдать"
соединитель -> "и" «¦_
союз -> "где" *
союз — > "если"
отношение ~> "является"
отношение -> "равно"
предикат —> (определяется в факте "схема")
аргумент — > (любое слово)
Программа "зобъект"
Программа "зобъект" работает аналогично программе "объект" из разд. 5.2.
% имена переменных: ;.';
% Р = имя предиката
% А = имя аргумента
% V = значение аргумента
% Valuehst = список значений аргументов
% Tlist, Printlist, Qlist =
% [t(P,A,V),t(P,A,V),...] 4
% I - входной список слов ;:
5.5. ЯЗЫК ЗАПРОСОВ 241
% R, R1,0 = остаток списка слов
% нетерминалы:
зобъект A,0, предложение, Tlist, Printlist-) :—
зобъект (I, R, команда, _, _),
зобъект(R, Щ,па_список, Printlist, _),
зобъект (R 1,0, уточнение, Qlist, _),
присоединить (Printlist, Qlist,Tlist).
зобъект A,0, па_список, [т(Р, А, V) | Tlist], _) :-
зобъект (I, R,na, т(Р, А, V), _),
зобъект (R, R1, соединитель, _, _),
зобъект (Rl,O,na_cnHcoK, Tlist, _).
зобъект (I,О,па список, [т(Р, А, V) ], _) :-
зобъектA,О,па, т(Р, А, V), _).
зобъектA,0,па, т(Р, А, V), _ ) :-
% сгенерировать уникальную переменную V:
зобъект (I, R, предикат, Р, _),
зобъект (R,О,аргумент, А, _).
% унифицировать V в первом "па" с V во втором "па"
зобъект A,0,уточнение, [т(Р1, А1, V), т(Р2, А2, V)], _) :-
зобъект (I, R, союз, _, _),
зобъект (R, Rl,na, т(Р1, А1, V) , _),
зобъект (Rl, R2, отношение, _, _),
зобъект (R2,0,na, т(Р2, А2, V) , _).
зобъект (I, I, уточнение, [],_). % пустая продукция.
% терминалы:
зобъект ([выдать j R], R, команда, _,_).
зобъект ([Р [ R], R, предикат, Р, _) :- предикат(Р, _).
зобъект ([Имяарг | R], R, аргумент, Имяарг, _).
зобъект ([является \ R], R, отношение, _, _).
зобъект ( [равно J R], R, отношение, _, _).
зобъект ([и | R], R, соединитель, _, _).
зобъект ( [где | R], R, союз, _,_).
зобъект ( [если j R], R,cok>3,_,_).
предикат (Имяпред, Кол_во_арг) : —
схема (Имя пред, Список), length (Список, Кол_во_арг).
Алгоритм работы программы "зобъект
Процедура "зобъект" имеет на два аргумента больше, чем процедура
"объект". Через четвертый аргумент процедуры "зобъект" возвращается
результат процесса грамматического разбора. Например, если будет обна-
242 ГЛ. 5. ОБРАБОТКА ТЕКСТА
ружен объект "па" (предикат + аргумент), то процедура разбора возвратит
структуру, состоящую из предиката, аргумента и значения:
т(Р, А, V)
Список таких структур строится нетерминалами "па_список" и "уточ-
"уточнение". Построенные списки объединяются в один список в нетерминале
"предложение". Список структур, вырабатываемый нетерминалом "пред-
"предложение", содержит все аргументы, к которым нужно обратиться в итого-
итоговом Пролог-запросе. Пятый аргумент процедуры "зобъект" используется
только в правиле "предложение"; он является списком всех структур,
которые требуется вывести иа печать после выполнения Пролог-запроса.
Выходные данные процедуры грамматического разбора
Можно проверить работу процедуры грамматического разбора, проана-
проанализировав результаты, которые вырабатывает тестовый запрос.
] ?- зобъект (
[выдать, служащий, имя, и, отдел, менеджер, где,
код, служащий, является, отдел, код],
[],предложение, Tlist,Printlist).
Tlist = [ т(служащий, имя, __613),
т(отдел, менеджер, _642),
т(служащий, код, _668),
т (отдел, код, _668) ]
Printlist= [ т(служащий, имя, _613),
1 (отдел, менеджер, _642) ]
Заметьте, что в списке «Printlist» содержатся только те структуры, к
которым имеется обращение из "па_список" после команды "выдать".
Поэтому список «Printlist» является подмножеством списка «Tlist».
Список «Tlist» содержит все объекты "па", упомянутые в запросе. В
результате действия правила "уточнение" одна и та же переменная _668
появляется и в структуре, несущей информацию о служащем, и в структу-
структуре со сведениями об отделе.
Процедура "построить_псписки"
Следующей задачей будет объединение каждого множества струк-
структур "т" с одинаковыми именами предикатов в список, состоящий из имени
предиката и пар имя/значение аргумента. Каждая пара имя/значение аргу-
аргумента обозначается идентификатором « AVpair » и записывается в виде
структуры «п(Имя, Значение)». Итоговый список таких структур носит
название «Plist».
5.5. ЯЗЫК ЗАПРОСОВ 243
Пусть, к примеру, в списке «Tlist», построенном процедурой грамма-
грамматического разбора, содержатся две структуры "т":
[т(служащий,имя,_1), т(служащий,код,_2)]
Тогда будет сгенерироввИ'теной>'сдаюок «^Ptost^ ч<.»л1' •
[служащий, п(имя,г1),п(код,_2)]г;м ,^ >10^,i , ч л
Процедура "построигь^псписки" берет в качестве входного аргумента
список «Tlist», выработанный процедурой "зобъект", а затем генерирует
список «Plists», каждым элементом которого является список
«Plist». Каждому списку «Plist» соответствует отдельный предикат,
встречающийся в списке « Tlist » . Процедура "построить л списки" отсле-
отслеживает предикаты, которые она уже обработала, помещая их во второй
аргумент, обозначаемый идентификатором «Donelist». Когда процедура
"построить_псписки" встречает необработанный предикат, она вызывает
процедуру "построить_парыАЗ" для построения структур "п" по всем
структурам "т" из списка «Tlist», содержащим этот предикат. Вызов
процедуры "унифицировать_перем" преобразует получившийся список
структур "п" таким образом, что переменные, несущие информацию о зна-
значениях аргументов, унифицируются в тех случаях, когда совпадают имена
аргументов. Например, если в список структур « AVpairsl » (входная
информация для процедуры "унифицироватьлерем") входят такие две
структуры "п":
[п(имя,_50),. . . п(имя, -65)],
то в списке структур «AVpairs2 » (выходная информация процедуры
"унифицировать_перем") будут унифицированными такие неконкрети-
зированные переменные:
[п(имя, _50), . . . п(имя, ~50)].
Этот шаг необходим для сохранения любых унификаций, выполненных
процедурой грамматического разбора.
% имена переменных:
%Р = имя предиката
% А = имя аргумента
% V = значение аргумента (неконкретизированная
% переменная)
% Tlist = [t(P,A,V),t(P,A,V), ...]
%AVpairs = [п(А, V),n(A,V),. ..]
% Plist = [P, n(A,V),n(A,V),...]
% Plists = список, каждый элемент которого - это список Plist
% построить_псписки:
44 ГЛ. 5. ОБРАБОТКА ТЕКСТА
% преобразовать список структур т (Р, А, V) в
% Р + список структур п (А, V).
% + + -
ПОСТрОИТЬ-ПСПИСКИ ([],_, []).
% пропустить структуру т (Р, А, V), если значение Р содержится в
% списке Donelist:
построить_псписки ([т(Р, А, V)! Tlist], Donelist, Plists) :—
элемент (Р, Donelist),
!, построить_псписки (Tlist, Donelist, Plists).
% в противном случае обработать Р:
построить-псписки ([т(Р, A, V)| Tlist], Donelist,
[[р; AVpairs2 ] ! Plists]) :-
построить_лтарыАЗ (Г, [t(P,A,V)| Tlist], AVpairsl),
унифицировать_перем (AVpairsl, AVpairs2),
% добавить Р в список Donelist:
!, построить_псписки (Tlist, [P ! Donelist],Plists).
% построить л ары A3:
% построить список структур п(А, V) для одного предиката.
% + + -
построить_парыАЗ (_, [ ], [ ]).
% Р (первый аргумент) согласуется с Р, входящим в структуру
%т(Р, А, V), поэтому добавить структуру п(А, V) в список AVpairs:
построить_парыАЗ (Р, [т(Р, А, V) | Tlist],
[п(А, V)! AVpairs]) :-
!, построить_парыАЗ (Р, Tlist, AVpairs).
% Р 1 не согласуется с Р2, поэтому продвинуться вперед:
построить_парыАЗ (Р1, [т (Р2, А, V) \ Tlist], AVpairs) :-
!, построить_парыАЗ (PI, Tlist, AVpairs).
% + -
унифицировать_перем ([ ], [ ]).
унифицировать_перем ([п(А, V) | In_AVpairs],
[п(А, V); Out_AVpairs] ) :- ,
% "элемент" унифицирует V с V, когда А согласуется с А:
элемент (п (А, V), In_AVpairs),
!, унифицировать_перем (In_AVpairs, Out_AVpairs).
унифицировать_перем ([п (А, V) j In_AVpairs],
[п (А, V) I Out_AVpairs] ) :-
% если подцель "элемент" потерпит неудачу, перейти к
% следующей паре:
!,унифицировать_перем (In_AVpairs, Out_AVpairs).
5.5. ЯЗЫК ЗАПРОСОВ 245
Выходные данные программы "построить—псписки"
Посмотрим, что процедура "построить_псписки" сделает с выходными
данными предыдущего запроса к процедуре "зобъект":
| ?— построить_псписки (
[т (служащий, имя, _613),
т (отдел, менеджер, _642),
т (служащий, код, _668),
т(отдел, код. _668)],
[ ], Псписки) .
Псписки = [[служащий,п(имя, -613),п(код, -668)j ,
[отдел, п(менеджер, -642) ,п(код, -669]]
Процедура "построить—псписки" сгруппировала список структур "т" в
два списка « Plist >).
Процедура "построить_зсписки"
Следующая задача состоит в том, чтобы по базе данных "схема" опре-
определить количество аргументов каждого предиката, для которого сущест-
существует список «Plist » . Необходимо построить список аргументов для каж-
каждого предиката. Этот список должен содержать взятые из « Plist » пере-
переменные, несущие значения аргумента, которые должны располагаться в
списке в правильных позициях. В остальные позиции списка следует по-
поместить новые переменные. Пусть, к примеру, требуется преобразовать
список «Plist » вида:
[служащий, п (оклад, _25) ]
в новый список, состоящий из имени предиката и того же количества ар-
аргументов, что и у базы данных "служащий":
[служащий, _,_,_, _25]
Обратите внимание на то, что переменная, несущая значение аргумента
"оклад", располагается в правильной (четвертой) позиции запроса к базе
данных "служащий". Преобразованный список «Plist» получает назва-
название « Qlist» . Далее этот список будет трансформирован в запрос языка
Пролог.
Процедура "построить_зсписки" берет в качестве входного элемента
список «Plist», выработанный процедурой "построить_псписки", и воз-
возвращает список « Qlists » . Процедура "построить_зсписки" анализирует
"схему" каждого предиката из списков <<Plist» и возвращает «Argna-
mes» - список имен аргументов, связанных с предикатом. Затем она
вызывает процедуру "построить_список_значений", которая вырабаты-
вырабатывает «Valuelist» — список, состоящий точно из такого количества пере-
переменных, сколько насчитывается переменных в списке « Argnames » . Спи-
246 ГЛ. 5. ОБРАБОТКА tEKCTA
сок « Qlist » строится путем добавления имени предиката в начало списка
« Valuelist».
Процедура "найти_пару_для_арг" вызьтается процедурой "постро-
ить_список_значений". На ее вход поступают имя аргумента и список
структур "п". Если процедура "найти_пару_ддя_арг" сможет обнаружить
указанное' имя эаргу1йеКЙ^% эпШёЙтё"ЙгЫй«а^'^М>"вйа возвратит перемен-
переменную, несущую значение этого аргумента. В противном случае процедура
возвратит новую переменную.
% имена переменных: ¦{»• ¦>¦
% Argnames = список име'н аргументов
% V, VI, V2 = значения аргументов ,
% Valuelist = список значений аргументов
%AVpairs = [n(A,V),.. .] '.."""
% Plist = [Р, n(A,V),n(A,V),. ..] '
% Plists = список, каждым элементом которого является список
% Plist ' " - ,•
% Qlist = [Р, VI, V2,. . . VN] &
% Qlists = список, каждым элементом которого является спи
% Qlist ""#¦
¦¦>#¦'
% построить_зсписки: построить список, состоящий из списков QlistT
построить_зсписки ([ ], [ ]). v „ ,г, ?
построить_зсписки ([ [Р 1 AVpairs] ] R], <¦.; .••..;>» ,*'
[ [Р! Valuelist] ! Qlists]):-,;- j& ЛТ\
схема (Р, Argnames), ¦-:• >'¦ '.vn
построить_список_значений (Argnames,AVpain.VahieUet), -4$
!, построить_зсписки (R,Qlists). ., • "•.¦¦•»: "¦#¦'!
%построить_списки_значений: >¦« \ ¦¦¦ь:
% искать каждое А из списка Argnames в списке . . .¦•...,-.
% AVpairs; возвратить список значений.
% + + -
построить_список_значений ([],_, []). ' *''!'
¦ .; ' >..» к*
построить_список_значений ([А | Argnames],
AVpairs, [V! Valuelist]) :- ".' |
найти_пару_для_арг (А, V, AVpairs), 1
!, построить_список_значений (Argnames, AVpairs, Valuelist).
% найти_пару_для_арг:
% если А (первый аргумент) обнаружен в списке AVpairs, то через вто-
%рой аргумент вернуть nepeMeHHyroV; в противном случае вернуть пе-
% ременную
найти_пару_для_арг (_,_,[]).
5.5. ЯЗЫК ЗАПРОСОВ , 247
найти_пару_ддя_арг (А, V, [п(А, V) | AVpairs]) :-!.
найти_пару_ддя_арг (A,V, [п (НеА,_)! AVpairs]) :-
!,найти_пару_ддя_арг (А, V, AVpairs).
Выходная информация программы "цвстроить^зслнски"
Приведем запрос к процедуре "построить_зсписки", входным аргу-
аргументом в котором служит список Plists, полученный при предыдущем
запросе к процедуре "построить_псписки".
! ?— построить_зсписки (
[ [служащий, п (имя, _613), п (код, _668) ],
[отдел, п (менеджер, _642), п (код, _668) ] ],
Qlists).
Qlists = ff служащий, -613, -668, -868, -885],
(отдел, -668, -922, -642]]
Обратите внимание на положение каждой переменной в выходном списке
Qlists. Внутренняя переменная программы _668 появляется в обоих спис-
списках Qlist, входящих в состав списка Qlists. Она выступает в роли разделяе-
разделяемой (т.е. общей) переменной в итоговом составном запросе.
Процедура "список_во_фразу"
Для преобразования списка Qlists в подцели составного запроса необ-
необходимо воспользоваться встроенным предикатом "=.." (см. разд. 3.9).
Процедура "список_во_фразу" выполняет это преобразование для лю-
любого количества списков Qlist. Подцели составного запроса объединяются
друг с другом при помощи инфиксной операции,. Это означает, что если
первым аргументом предиката "=.." будет составной запрос, то этот пре-
предикат превратит символ , в первое слово выходного списка:
! ?- (OTe4(X,Y),OTe4(Y,Z)) =.. Список.
Список =[ ,, отец (X, Y), отец (Y, Z)]
Примечание: первым элементом списка "Список" является запятая; за
ней стоит еще одна запятая, которая отделяет первый элемент от следую-
следующего - «отец(Х, Y)». Правила B) и C) процедуры "список_во_фра-
зу" предназначены для обработки составных запросов.
% имена переменных:
% Tlist, Printlist = [т(Р, А, V),
% t(P,A,V),...]
% Qlist = [Предикат, Aprl, Арг2,.... AprN]
% Qlists = список, каждым элементом которого является список Qlist
% преобразование списка Qlists во фразовую форму записи.
248 ГЛ. 5. ОБРАБОТКА ТЕКСТА
% точно один список Qlist:
% + -
список„во_фразу ([Qlist], Фраза) :- % A)
Фраза =. . Qlist , ! .
% точно два списка Qlist:
список__во_фразу ([QlistI, Qlist2] , ФразаЗ) :- % B)
Фраза 1 =. . Qlist 1,
Фраза2 =. . Qlist2,
% связать друг с другом фразы Фраза1 и Фраза2 при помощи со-
% единителя ","
ФразаЗ =.. [,, Фраза1, Фраза2],! .
% более двух списков Qlist:
список_во_фразу ([Qlist11 Qlists], ФразаЗ) :— % C)
Фраза1 =. . Qlist 1,
список ..во^фразу (Qlists, Фраза2) ,-
% связать друг с другом фразы Фраза 1 и Фраза2 при помощи со-
% единителя ","
ФразаЗ =. . [,, Фраза1, Фраза2],! .
Выходные данные процедуры "список_во_фразу"
Если на вход процедуры "список_во_фразу" подать выходные дан-
данные процедуры "построить_зсписки", то будет выдана следующая ин-
информация:
! ?— список_во_фразу(
[ [служащий, __613, _668, _868, __885],
[отдел, _668, _922, _642] ],
Запрос).
Запрос = служащий (-613, -668, -868, -885),
отдел (-668, -922, -642)
Теперь посмотрим, что произойдет при выполнении приведенного выше
запроса « Запрос » ¦
; ?- Запрос = (служащий(_613,_668,_868,_885),
отдел (_668,_922,_642)), j
Запрос. 1
Запрос = (служащий (брайен, 100, оператор, 20000) ,
отдел A00, обработка-данных, ральф)) ;
Запрос = (служащий (нэнси, 200, начальник, 71000),
отдел B00,продажа,жб) ) ;
5.5. ЯЗЫК ЗАПРОСОВ 249
Процедура "печатать_тсписок"
Осталось только напечатать требуемые имена предикатов, имена аргу-
аргументов и значения переменных. Процедура грамматического разбора вы-
выдавала через переменную "Printlist" список структур "т", который сле-
следовало напечатать. Текст процедуры "печатать_тсписок" будет следующим:
печатать—тсписок ([ ]) :— nl, ! .
печатать_тсписок ([т (Р, А, V) | Printlist]) :-
write (P), write (' '),
write (A), write (' '),
write (V), write (' '),
!, печатать__тсписок (Printlist).
Нижеследующий запрос иллюстрирует работу процедуры "печатать_тспи-
сок":
] ?- печатать_тсписок ([т(служащий, должность, начальник),
т(отдел, имя, продажа) ]).
служащий должность начальник отдел имя продажа
да
Объединение составных частей в единую программу
Правило "запрос", приводимое ниже, объединяет все составные части
программы, работающей с языком запросов, в единое целое.
запрос :—
iv читатьпредложE),
I зобъектE, [], предложение, Tlist,
I Printlist),
I'- !,
I построить_псписки (Tlist, [], Plists),
» построить—зсписки(Plists, Qlists),
список_во„фразу (Qlists, Запрос),
l Запрос,
f печатать_тсписки (Printlist).
[Заметьте, что на вход каждой подцели, располагающейся после подцели
"читатьпредлож", поступает список, который затем определенным обра-
образом трансформируется, а потом передается следующей подцели. Проце-
Процедура "зобъект" вырабатывает сразу и список « Tlist » , который служит
входным аргументом процедуры "построить_псписки", и список
« Printlist », который является входным аргументом процедуры "печа-
;тать_тсписки". Предикат "сократить", стоящий после подцели "зобъект",
гарантирует, что запрос, пересылаемый через переменную S, будет под-
подвергаться грамматическому разбору только один раз.
250 ГЛ. 5. ОБРАБОТКА ТЕКСТА
Интерпретатор
Правило "язык —запросов" основывается на правиле "запрос", которое
может выдавать ответы на неограниченное количество запросов пользова-
пользователя. Каждый раз пользователю посылается сообщение—подсказка "?".
После того, как процедура "язык—запросов" будет запущена, она станет
действовать' как интерпретатор языка запросов. Пример сеанса работы
с процедурой "язык_запросов":
% интерпретатор языка запросов:
язык_запросов :— '._•¦.
repeat, write ('?'), запрос, fail.
I ?— язык_запросов.
? выдать служащий имя. ь~
служащий имя брайен -
служащий имя нэнси ' ¦ '
служащий имя ральф . '
? выдать служащий имя и служащий оклад
где служащий имя является отдел менеджер
(В переводе с языка запросов на русский это будет звучать так: "Выдать
имя и оклад служащего, являющегося менеджером отдела".)
служащий имя ральф служащий оклад 71500
(имя служащего - Ральф, а его оклад - 71500 долларов.)
БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ
- Стратегии грамматического разбора рассматриваются в книге [1].
Аналогия между грамматическим разбором и дедуктивным процессом
отмечается в работе [85]. В работе [65] представлена гибкая система
восходящего грамматического разбора, реализованная на Прологе. Реали-
Реализация на Прологе общепринятых языков запросов к базам данных подроб-
подробно обсуждается в книге [61].
УПРАЖНЕНИЯ
1. Напишите запрос к процедуре "читатьпредлож" и введите предло-
предложение. Что получится, если введенное предложение будет занимать более
одной строки? Что произойдет, если в конце предложения не будет стоять
точка? Что будет, если на строке располагаются несколько предложений,
каждое из которых заканчивается точкой?
УПРАЖНЕНИЯ 251
2. Напишите новый предикат "вводстроки", который отличается от
"читатьпредпож" только тем, что он учитывает все слова, расположенные
в одной строке (включая точки) и возвращает их в виде списка.
3. Напишите составной запрос, в котором употребляется процедура
"читатьпредпож" для ввода предложения пользователем, а затем исполь-
используется процедура "объект" (см. разд. 5.2) для грамматического разбора
предложения.
Напишите запрос, который генерирует все возможные предложения из
слов, находящихся в словаре программы.
Воспользуйтесь отладочными средствами, чтобы посмотреть, что про-
происходит при разборе нескольких групп существительного как при наличии,
так и при отсутствии прилагательных.
Попытайтесь ввести другие расширения принятой грамматики, та-
такие, как:
1) переходные и непереходные глаголы,
2) наречия,
3) составные сказуемые.
4. Напишите составной запрос, в котором для ввода пользователем
группы существительного употребляется процедура "читатьпредлож",
а затем для грамматического разбора применяется процедура
"восх_объект" (см. разд. 5.3).
Воспользуйтесь отладочными средствами для наблюдения за ходом
грамматического разбора нескольких групп существительного. Введите
те же словосочетания, которые Вы употребляли в упр. 3, и сравните ре-
результаты трассировки выполнения данной программы с трассировкой
выполнения процедуры нисходящего грамматического разбора.
При каких условиях левая рекурсия в процедуре восходящего грам-
грамматического разбора будет более эффективна, чем правая рекурсия в про-
процедуре нисходящего разбора?
5. Напишите запрос с использованием синтаксиса рассмотренного язы-
языка запросов, чтобы выдать лишь имена всех менеджеров отделов. Напи-
Напишите запрос, позволяющий вывести оклады и имена менеджеров отделов.
6. Напишите новую версию процедуры "читатьпредлож", которая
сможет считывать фразы языка Пролог и преобразовывать их в форму, при-
пригодную для использования процедурой "c/_ro_m". Существует ли способ
обработки операции ":—", позволяющий трактовать ее как самостоятель-
самостоятельное слово?
7. Разработайте интерфейс языка запросов с другими уже имеющимися
У Вас базами данных Пролога.
8. Добавьте дополнительные средства в язык запросов — другие отно-
отношения, помимо отношения "является", и команду "суммировать". Ко-
Команда "суммировать" должна вычислять итоговую сумму значений одного
из числовых полей для всей базы данных.
ГЛАВА 6
ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
6.1. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ ПРИ ПОМОЩИ ПРОЛОГА
Во многих прикладных задачах искусственного интеллекта требуется
представление знаний о мире. Для того чтобы понять, как этим целям
может служить Пролог, полезно рассмотреть некоторые общие характе-
характеристики формализмов представления.
Исчисление предикатов
Слово система употребляется в данной книге для обозначения не'ко-
торой ограниченной части мира. Знания о системе эквивалентны анализу
структуры системы.
Как отмечалось в разд. 0.5, исчисление предикатов первого порядка
служит примером формализма представления, потому что прн помощи
аксиоматической теории логики предикатов можно описать структуру
системы. Несколько тривиальных примеров таких теорий были даны
в разд. 0.5. Наличие полного множества правил вывода дает возможность
выводить логические следствия аксиоматической теории. Формальный
смысл аксиоматической теории — это множество всех следствий, кото-
которые могут быть получены из нее при употреблении логически коррект-
корректных правил вывода. Интерпретация теории — это приписывание каждого
из символических обозначений, встречающихся в теории, определенным
компонентам (сущностям, функциям или отношениям) системы. Теория
будет точно описывать систему, если при должной интерпретации все след-
следствия теории будут истинными для системы.
Вычислительные формализмы
Для представления знаний разработан ряд вычислительных формализ-
формализмов. Правда, нужно сказать, что большая часть этих формализмов не обла-
обладает такой выразительной силой, как исчисление предикатов первого по-
порядка. Излагаемый далее материал в целом касается большинства пред-
предложенных вычислительных формализмов. Вычислительный формализм
состоит из двух частей:
1) дескриптивный язык и * Ч
6.1. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ ПРИ ПОМОЩИ ПРОЛОГА 253
2) множество процедур, способных реализовать формальный смысл
описания, составленного на дескриптивном языке; это множество про-
процедур иногда называют обрабатывающей структурой формализма.
Формальный смысл описания
Представление знаний о системе при помощи вычислительного фор-
формализма равнозначно описанию существенно важных аспектов структу-
структуры системы при помощи-дескриптивного языка этого формализма. Фор-
Формальный смысл описания системы состоит во всех возможных ответах
и поведенческих актах обрабатьтающеи структуры данного формализма,
которые могут быть порождены на основе приведенного описания. Фор-
Формальный смысл описания аналогичен множеству следствий аксиоматичес-
аксиоматической теории исчисления предикатов, а обрабатывающая структура форма-
формализма аналогична множеству правил вывода.
Формальный смысл описания — это продукт, порождаемый обрабаты-
обрабатывающей структурой формализма. Следовательно, обрабатывающая струк-
структура накладывает на этот смысл определенные ограничения. Некоторые
формализмы предоставляют программисту возможность добавлять новые
процедуры к обрабатывающей структуре, что позволяет расширить диапа-
диапазон возможных формальных смыслов дескриптивного языка.
Конечной целью представления знаний о системе является создание
программы, поведение которой будет отражать структуру системы в опре-
определенном существенно важном аспекте. Если удастся составить такую
программу, то она сможет решать задачи, связанные с системой, или моде-
моделировать поведение системы.
Пролог служит примером такого формализма. Использование язы-
языка Пролог для представления знаний обсуждается в оставшейся части
данного раздела, а другие формализмы рассматриваются в последующих
разделах настоящей главы.
Пролог как вычислительный формализм
Дескриптивный язык Пролога — это логика предикатов, представлен-
представленная в форме фраз Хорна. Обрабатывающая структура Пролога состоит
из интерпретатора, к которому добавлен ряд встроенных предикатов
(таких как "is/2") и, возможно, некоторых процедур общего назначе-
назначения (таких как "findall/З"). При помощи Пролог-программы можно
представить знания о системе почти таким же образом, как при помощи
аксиоматической теории логики предикатов можно описать область знаний.
(В явном виде это можно выразить так: каждая фраза Пролог-программы
эквивалентна аксиоме, а вся программа эквивалентна теории). Формаль-
Формальный смысл Пролог-программы — это множество истинных конкретных
реализаций отношений, которые могут быть выведены интерпретатором
на основании фраз программы.
254 ГЛ.6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Процесс представления знаний
Процесс представления знаний с помощью Пролог-программы может
состоять из следующих этапов :
1. Специалист, знакомый с системой, анализирует ее структуру для
того, чтобы выделить все значимые сущности и важные отношения между
этими сущностями.
2. Программист выбирает символические обозначения для представле-
представления каждой сущности и каждого отношения.
3. Специалист по системе определяет каждое отношение семантически,
при этом отмечается, какие конкретные реализации отношения будут
истинными, а какие — ложными.
4. Программист аксиоматически определяет каждое отношение при
помощи фраз языка Пролог. Аксиоматическое определение будет пра-
правильным, если интерпретатор Пролога сможет вывести из этого опреде-
определения каждую истинную конкретную реализацию данного отношения.
После того как знания о системе будут описаны в Пролог-программе,
пользователь сможет обращаться к этим знаниям посредством запросов
или при помощи более совершенного интерфейса программы с пользо-
пользователем.
Пример представления знаний
В качестве примера рассмотрим систему, образованную межличност-
межличностными отношениями работников завода. Начальник цеха, хорошо разби-
разбирающийся в этой системе, проводит ее анализ и разбивает систему на сле-
следующие компоненты. Каждый служащий (Мери Кравиц, Боб Джонс, Сэм
Финкл и Патриция Хендрикс) — это значимая сущность. Каждая рабочая
смена (дневная и вечерняя) — это также значимая сущность. Отношение
между служащим и сменой, в которую он работает, является важным.
Отношение между служащими, которые знают друг друга, также является
важным.
Программист выбирает следующие символические обозначения этих
сущностей и отношений:
«мери», «боб», «сэм» и «патриция» - это служащие;
«дневная»и «вечерняя» — это смены;
<<раб_смена» — это отношение между служащими сменой,в которой
он работает;
« знает » — это отношение между служащими, которые знают друг
друга.
Начальник цеха семантически определяет отношение "раб_смена",
устанавливая, что истинны следующие конкретные реализации этого отно-
6.1. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ ПРИ ПОМОЩИ ПРОЛОГА 255
шения:
раб_ смена (мери, дневная)
раб_ смена (сэм, вечерняя)
раб_ смена (боб, вечерняя)
раб_ смена (патриция, вечерняя)
а все остальные конкретные реализации - ложны. Начальник цеха опре-
определяет отношение "знает", утверждая, что любые два лица, работающие
в одну и ту же смену, знают друг друга. Из этого следует, что истинны-
истинными будут такие конкретные реализации отношения "знает":
знает (сзм, боб)
знает (боб, сэм)
знает (сзм, патриция)
знает (патриция, сэм)
знает (боб, патриция)
знает (патриция, боб)
Все остальные конкретные реализации этого отношения будут ложны-
ложными. Программист, "вооружившись" этими семантическими определения-
определениями, определяет отношение "раб_смена" аксиоматически, при этом каж-
каждая истинная конкретная реализация данного отношения записывается в
виде факта:
% Служащий Смена
раб_смена (ме ри, днев ная).
раб_смена(сэм, вечерняя).
раб_смена (боб, вечерняя).
раб_смена (патриция, вечерняя).
Отношение "знает" можно определить посредством правила (а не как
совокупность фактов), обращающегося к отношению "раб_смена":
знает (А, Б) :-
раб_ смена (А, Смена),
раб_ смена (Б, Смена),
А\==Б.
Проверка корректности данных аксиоматических определений состоит
в необходимости продемонстрировать то, что интерпретатор языка Пролог
сможет вывести из них все истинные конкретные реализации каждого
отношения (см. разд. 1.4).
256 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Формальный смысл
Символические обозначения, используемые для представления сущ-
сущностей и отношений в такой Пролог-программе, имеют как формальный
смысл, выражаемый через другие символические обозначения, так и внеш-
внешний смысл, который связывает их с компонентами представляемой сис-
системы. Для того чтобы оценить по достоинству силу Пролога как формализ-
формализма, полезно подробно рассмотреть природу обоих типов смысловых зна-
значений.
формальный смысл символического обозначения, употребляемого в
Пролог-программе, является продуктом дескриптивных фраз программы
и обрабатывающей структуры Пролога. Рассмотрим формальный смысл
символического обозначения отношения (т.е. имени предиката), исполь-
используемого в Пролог-программе. С формальной точки зрения отношение -
это отображение и термов-переменных (где п — количество аргументов)
на истинностное значение (см. разд. 0.5). В Пролог-программе отноше-
отношение определяется аксиоматически множеством фраз языка Пролог. Интерп-
Интерпретатор — это процедура, обладающая способностью выводить истинные
конкретные реализации отношения из фраз, определяющих это отноше-
отношение. С этой точки зрения интерпретатор реализует смысл аксиоматическо-
аксиоматического определения отношения. Формальный смысл символического обозначе-
обозначения отношения — это множество истинных конкретных реализаций отно-
отношения, которые могут быть выведены интерпретатором из фраз, содер-
содержащихся в программе.
Сходным образом формальный смысл терма, не содержащего пере-
переменных (т.е. константы или структуры без переменных), — это множест-
множество истинных конкретных реализаций отношений, в которые может вхо-
входить этот терм.
Внешний смысл
Для того чтобы обеспечить возможность представления знаний о ми-
мире при помощи Пролог-программы, символические обозначения програм-
программы (константы и имена предикатов и структур) должны обладать внеш-
внешним смыслом, связьтающим их с компонентами представляемой системы.
Этот смысловой уровень существует в умах программистов и пользова-
пользователей программы. Он сходен со смысловым значением слов естественного
языка. В приведенном выше примере программист выбрал символичес-
символическое обозначение «мери» для представления служащей Мери Кравиц,
следовательно, Мери Кравиц — это внешний смысл символического обоз-
обозначения «мери».
Для того чтобы сделать более ясной разницу между формальным и
внешним смыслом символических обозначений, рассмотрим фразу
знает (патриция, боб).
6.1 ПР1 ДСТАВЛЕНИЕ ЗНАНИЙ ПРИ ПОМОЩИ ПРОЛОГА
257
Описание
Обрабатывающая
структура
Выходная
информация
Приписывание символических обозначений
при описании компонент системы
Система (.часть мира)
Рис. 6 1
Формальный смысл символического обозначения "знает" — это множест-
множество истинных конкретных реализаций отношения"знаег/2". Частью формаль-
формального смысла символического обозначения "патриция" является то, что
данное обозначение может служить первым аргументом истинного конк-
конкретного случая отношения "знает/2". В приведенном выше примере под-
;разумеваемым внешним смыслом обозначения "знает" является зна-
рсомство друг с другом двух лиц, общающихся между собой в некото-
|рой социальной ситуации, а предполагаемым внешним смыслом симво-
Цяического обозначения «патриция); является человек по имени Патри-
|иия Хендрикс. Если выражаться в терминах логики предикатов, то внеш-
|ний смысл символического обозначения константы — это его значение
Яри некоторой интерпретации (см. разд. 0.5). Интерпретатор языка Про-
)г реализует формальный смысл символических обозначений; мы же
ак программисты и пользователи программы должны придать этим обоз-
ачениямвнешний смысл.
На рис.6.1 показано, как внешние смысловые значения связывают
символические обозначения программы с компонентами представляемой
системы.
Обманчивая природа внешнего смысла
Программа, предназначенная для представления знаний о системе,
окажется удачной, если пользователь сможет извлекать эти знания из
программы и использовать их способом, целесообразным для выпол-
выполнения действий с системой. Иными словами, поведение и выходная инфор-
информация программы должны отражать структуру системы. Если пользова-
пользователь обнаружит, что выходная информация программы противоречит
его пониманию системы, то это будет означать, что программа непригод-
непригодна для работы.
С точки зрения пользователя подразумеваемый внешний смысл сим-
символических обозначений, встречающихся в выходных данных, — это. ключ
9. Дж. Малпас
258 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
к знаниям, воплощенным в программе. Так, если внешний смысл, кото-
который пользователь придает символическим обозначениям в выходной
информации программы, будет отличаться от внешнего смысла, который
в них вкладывал программист, то пользователю может показаться, что
программа составлена некорректно.
Рассмотрим в качестве примера человека, который в первый раз нри-
шел в библиотеку с компьютеризированным каталогом. Программа спра-
спрашивает этого человека: «Тип книги?» , не давая никаких указаний о том,
что может обозначать слово <(тип». Пользователь судорожно пытается
сообразить, что же следует ввести в ответ - (( небеллетристика» ? <<иност-
<<иностранная» ? «красная»? Он в конце концов решает ввести слово << небел-
небеллетристика» , но программа отвергает это слово, сообщая, что {{небел-
{{небеллетристика - это неверный тип)). Пользователь знаком со структурой
каталога и предполагает, что эта структура корректно реализована в
программе. Однако для того, чтобы воспользоваться программой, он вна-
вначале должен выяснить, какой смысл программист вложил в символичес-
символическое обозначение «тип».
В качестве другого примера возьмем пользователя, работающего с
экспертной системой, которая якобы может анализировать личность чело-
человека. Согласно рекламе в программе реализованы и теория личности,
и методы психоанализа. В конце сеанса работы программа сообщает поль-
пользователю о том, что он "негибок". Но пользователь не думает о себе, что
он "негибок". Прав ли он? Если пользователь не знает, какой внешний
смысл придали авторы программы символическому обозначению "не-
"негибок", то перед ним открыты два пути: 1) пользователь может в конце
концов посчитать, что экспертная система не слишком "умна" или 2)
он может предположить, что программа знает, о чем говорит, и поэтому
попытается проанализировать, в чем именно проявляется, его "негиб-
"негибкость", признавая тем самым, что диагностика, выданная программой,
правильна.
Внешний смысл символических обозначений - это "подводный ка-
камень" любой программы, представляющей знания, поскольку почти
всегда у конкретного символического обозначения существует более
чем одно внешнее смысловое значение. Символические обозначения, пред-
представляющие из себя неоднозначные слова естественного языка (как слово
«тин»), наиболее ненадежны в этом отношении. Для того чтобы сузить
диапазон внешних смысловых значений символического обозначения,
лучше всего делать более точными определения отношений, в которых
используются эти обозначения. К примеру, внешним смыслом обозна-
обозначения «мери», входящего в истинную конкретную реализацию отно-
отношения "раб _ смена /2" ;;
раб_смена(мери, дневная)
6.1. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ ПРИ ПОМОЩИ ПРОЛОГА 259
может быть любое количество людей, первое имя которых — Мери. Но
если при определении отношения добавить номер человека по социально-
социальному страхованию:
раб_смена(мери, 121 _76_7720, дневная)
то это существенно сузит круг лиц с именем "Мери", к которым будет
иметь отношение символическое обозначение «мери», если только дан-
данная конкретная реализация отношения "раб_смена/2" будет истинной
Представление знаний при помощи языка Си
Для того чтобы более четко проиллюстрировать то, какие преиму-
преимущества дает программисту использование вычислительного формализма
при представлении знаний, рассмотрим, как на процедурном языке (нап-
(например, на языке Си) можно составить программу, предназначенную дпя
представления знаний. Сам по себе язык Си не является вычислительным
формализмом. Поэтому для того, чтобы воспользоваться лкм языком
при представлении знаний, необходимо реализовать такой формализм в
рамках языка Си. В типичной Си-программе для этого требуется:
1) определение структур данных, конкретные экземпляры которых
будут использоваться для описания структуры системы, и
2) составление процедур, предназначенных дня вьшолнения вычисли-
вычислительных операций над экземплярами структур данных, иными словами,
для придания описаниям определенного формальною смысла.
Неопьяный программист, пользующийся языком Си, стремится изоб-
изобретать новые формализмы для каждой новой области применения (т.е.
дпя каждой представляемой системы). В результате этого тип формально-
формального смыслового значения, реализуемого процедурами программы, будет
сильно зависеть от конкретных особенностей представляемой системы.
Обратите внимание на то, насколько сильно это отличается от языка Про-
Пролог: символическое обозначение отношения в Пролог-программе имеет
один и тот же тин формального смыслового значения независимо от того,
какая система представляется. Самым большим недостатком введения
новых формализмов для каждой новой области применения является
то, что лицу, пытающемуся прочитать программу, потребуется изучить
как ее формализм, так и описание системы, реализованное структурами
данных этой программы.
С другой стороны, опытный программист, работающий с языком Си,
разработает формализм только для одной области применения, а затем
попытается использовать его в максимально возможной степени в дру-
других областях — просто потому, что это сэкономит много сил при сопро-
сопровождении программы. На языке Си можно реализовать весьма мощные
9*
260 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
формализмы. Примерами таких формализмов могут служить инстру-
инструментальное средство "уасс" операционной системы UNIX, а также реали-
реализации Пролога, написанные на языке Си.
Расширение языка Пролог
Взгляд на Пролог как на формализм, предназначенный для пред-
представления знаний, является слишком большим упрощением, так как при
этом не учитываются ни побочные эффекты, ни процедурная семантика
Пролога. Сейчас целесообразно дать более точное определение дескриптив-
дескриптивного языка и обрабатывающей структуры Пролога.
Фразы, не имеющие побочных эффектов, обладают четким деклара-
декларативным смыслом. Их следует рассматривать как часть дескриптивного
языка Пролога. Побочные эффекты (такие как встроенные предикаты
"сократить", "assert", "retract", "fail" и т.д.) - это строго процедурные
элементы Пролога, иснользуемме для управления стратегией решения
задач интерпретатора. Поэтому фразы, в состав которых входят побоч-
побочные эффекты, приобретают осмысленность только при процедурном проч-
прочтении. Некоторые процедуры общего назначения, такие как "findall",
выполняют вычисления, которые невозможны в Прологе без использова-
использования побочных эффектов. Поэтому такие процедуры можно рассматривать
как расширение обрабатьшающей структуры Пролога.
Интересно отметить, что несмотря на то, что в телах правил, опреде-
определяющих процедуру "findall", применяются побочные эффекты, вызов
процедуры "findall" обладает декларативным смыслом. Иными словами,
вызов процедуры "findall" объявляет отношение между запросом и все-
всеми .ответами на него, которые можно получить в соответствии с текущей
программой. Выше отмечалось, что обрабатывающая структура форма-
формализма — это множество процедур, способное реализовать формальный
смысл описания, записанного на дескриптивном языке формализма. До-
Добавление процедуры "findall" к обрабатывающей структуре Пролога рас-
расширяет диапазон возможных формальных смысловых значений дескрип-
дескриптивного языка Пролога. Вызов процедуры "findall" является дескриптив-
дескриптивным элементом. Он может быть подцелью фразы, являющейся в других
отношениях декларативной, при этом декларативная семантика даннок
фразы не будет нарушена. Процедура "findall " ни в какой степени не за-
зависит от конкретной области применения и, будучи реализованной один
раз, она может быть неоднократно использована во многих приклад-
прикладных программах.
Однако когда побочные эффекты применяются во фразах, ориенти-
ориентированных на конкретные приложения, то различие между дескриптив-
дескриптивным языком Пролога и его обрабатывающей структурой исчезает, фразы
этого типа можно тоже рассматривать как расширение обрабатывающее
структуры Пролога, но только ориентированное на конкретное прим*-'-
6.1. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ ПРИ ПОМОЩИ ПРОЛОГА 261
нение. В определенном смысле программист, пишущий такие фразы,
изобретает формализм специально для избранной области применения,
что во многом походит на то, как начинающий программист, работающий
с языком Си, создает новые формализмы для каждой новой области при-
применения. Такие фразы не удается повторно использовать при переходе от
одной области применения к другой, поэтому они в некоторой мере под-
подрывают свойства Пролога как формализма.
Для того чтобы сохранить ясность Пролога как формализма, при прак-
практическом программировании рекомендуется следующее:
1) делать все фразы, ориентированные на конкретную область приме-
применения, чисто декларативными и
2) сводить в отдельные общецелевые процедуры те вычисления, кото-
*рые можно выполнить только с применением побочных эффектов.
^ Стиль программирования на языке Пролог более подробно обсуждает-
|сяв разд. 7.5.
I Другие вычислительные формализмы
Среди других вычислительных формализмов представления знаний,
)тличных от Пролога, можно назвать семантические сети, фреймы и объект-
io-ориентированное программирование. Эти формализмы обсуждаются
I следующих разделах.
Концептуальный охват логики предикатов как языка представления
ограничен двумя нижеследующими онтологическими предположениями
„.(т.е. предположениями о существовании) :
1) существуют сущности и
2) существуют отношения между сущностями. \
Пролог базируется на этих же предположениях, поскольку он тесно
связан с логикой предикатов. В каждом из других формализмов имеются
определенные встроенные в них концепции (такие как наследование,
принцип умолчания, объекты и др.)> предназначенные для организации
знаний. Преимущество этих концепций состоит в том, что они позволяют
легко описывать определенные виды знаний. Недостатком этих концеп-
концепций является то, что они могут навязывать программисту определенный
взгляд на мир и что могут существовать некоторые виды знаний, не под-
поддающиеся описанию при помощи данных концепций. Пролог является бо-
более общим вычислительным формализмом по сравнению с другими форма-
формализмами именно потому, что он свободен от встроенных концепций. Но в
идеале хотелось бы обладать преимуществами и Пролога, и иных форма-
формализмов. Желательно иметь возможность применять концепции представле-
представления знаний там, где они лучше всего для этого подходят, но чтобы при этом
не требовалось в обязательном порядке пользоваться данными концеп-
концепциями во всех ситуациях. Этого можно добиться, если на дескриптивном
языке Пролога описать концепцию представления знаний, принадлежащую
262 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
к другому формализму, и дополнить обрабатывающую структуру Пролога
процедурами, которые смогут реализовать смысл описания. Итоговый
эффект от такого расширения должен заключаться в добавлении дополни-
дополнительных выразительных средств в Пролог, являющийся формализмом, и
в предоставлении программисту дополнительных инструментальных
средств, с помощью которых можно организовывать знания.
Наследование
Наследование является примером концепции, глубоко встроенной
как в формализм фреймов, так и в объектно-ориентированный форма-
формализм. Наследование можно рассматривать как слабое правило вывода,
позволяющее конкретному фрейму или классу получать информацию от
общего фрейма или класса. Информация, получаемая при помощи меха-
механизма наследования, часто играет роль умалчиваемого значения, принято-
принятого в конкретном фрейме или классе. Позднее в данной главе будет деталь-
детально рассмотрено, как можно расширить Пролог для включения в ною ме-
механизма наследования.
6.2. СЕМАНТИЧЕСКИЕ СЕТИ
Узлы и дуги
В семантической сети сущности и классы сущностей ассоциируются
с узлами, а отношения между сущностями ассоциируются с дугами, соеди-
соединяющими узлы. Дуга, подсоединенная к единственному узлу, устанавли-
устанавливает свойство этого узла. Семантическая сеть позволяет выполнять вывод
по цепочкам, описываемым определенными типами дуг Например, в сети,
изображенной на рис. 6.2, узел «птица» обладает свойством «летает».
Узел << канарейка» соединен дугой с узлом << птица», поэтому можно
прийги к выводу о том, что узел «канарейка» также обладает свойством
<< летает».
Графические схемы семантических сетей служат удобным способом
изображения бинарных отношений и свойств. Обратите внимание на сход-
сходство между рис. 6.2 и изображениями отношений при помощи дуг и овалов
из гл. 1 и 2.
Важнейшей концепцией формализма семантических сетей является
иерархия, поэтому данный формализм особенно удобен для представле-
представления таксономии знаний. Каждый уровень таксономии представляется в
виде узла, который соединен дугами "является" с более высокими и более
низкими уровнями. К примеру, на рис. 6.2 «птица» -¦ это наивысший
уровень таксономии, а на следующем уровне могут располагаться различ-
различные виды птиц.
6.2. СЕМАНТИЧЕСКИЕ СЕТИ
263
птица
является
Q канарейка
является
твити
летает
цвет
живет с
Рис 6.2
желтый
с ильвестр
^темная порода ^ (
порода вулканичес-
вулканического происхождения
Ркс. 6.3
)
базальт
Однако если программист не предусмотрит должного разделения уров-
уровней таксономии, то возникнут проблемы. В примере, показанном на
рис. 6.3, программист разделил узел << горная порода», представляющий
все типы горных пород, на три подкласса.
Действительно, темные породы, породы вулканического происхожде-
происхождения и базальтовые породы являются типами горных пород. Но такая их
классификация в большей степени ведет к путанице, чем к ясности. Три
перечисленных подкласса не находятся на одном и том же уровне, и неко-
некоторые виды горных пород могут попасть более чем в один подкласс.
Этот пример показывает, что если программист не проанализирует кор-
корректно структуру системы, то не поможет никакая концепция органи-
организации знаний.
Семантическая сеть как Пролог-программа
Если рассматривать семантическую сеть как описание отношений,
которые поддерживаются между сущностями, то ее можно непосредст-
непосредственно реализовать при помощи языка Пролог. Нижеследующая програм-
264 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
ма выражает структуру сети с «птицами», представленную на рис. 6.2:
является (канарейка, птица).
является (твити, канарейка).
живет—с(сильвестр, твити).
летает(птица).
летает(X) :- является (X, У),летает(У).
цвет (канарейка, желтый).
цвет(Х,У): является (X,Z),цвет (Z,Y).
Вторая фраза "цвет" позволяет сделать вывод о том. ч7о ^твити>> - жел-
желтого цвета, так как «твиги» — это канарейка, а любая сущность, которая
является канарейкой, имеет желтый цвет. Вывод можно выполнить в лю-
любом месте, где два узла диаграммы связаны дугой "является". Дуга "явля-
"является" представляет либо отношение включения в класс (например, класс
канареек включается в класс птиц), либо отношение принадлежности к
классу («твити» - это член класса канареек).
6.3. ФРЕЙМЫ ,
Представление знаний о ситуациях
Мински создал концепцию фреймов как один из способов представле-
представления знаний о ситуациях [72]. Каждый фрейм содержит слоты (в букваль-
буквальном переводе - щели), которые идентифицируют тип ситуации или задают
параметры конкретной ситуации. К примеру, фрейм, описывающий ситуа-
ситуацию на вечеринке, может иметь слот тип, значение которого будет опреде-
определять тип вечеринки. В этом фрейме могут также присутствовать слоты
время и место, значениями которых будут параметры конкретной вече-
вечеринки. Формализм фреймов можно рассматривать как обобщение форма-
формализма семантических сетей. Иерархия — это одна из важнейших концепций
формализма фреймов, поэтому данный формализм также пригоден для
представления таксономии знаний.
Выражение, записанное на языке фреймов, таком как FRL [36], дек-
декларирует существование фрейма. В нижеследующем примере упоминаются
три фрейма - МЕРОПРИЯТИЕ, СОБРАНИЕ и СОБРАНИЕ _38. Фрейм
МЕРОПРИЯТИЕ - наиболее общий, фрейм СОБРАНИЕ- более конкретный,
описывающий вид МЕРОПРИЯТИЯ, а фрейм СОБРАНИЕ-38 - наиболее
уточненный фрейм, описывающий конкретное СОБРАНИЕ. Фрейм
СОБРАНИЕ называется субфреймом фрейма МЕРОПРИЯТИЕ, а фрейм
СОБРАНИЕ-38 будет субфреймом фрейма СОБРАНИЕ.
6.3. ФРЕЙМЫ
265
(СОБРАНИИ. имя,
(РАЗНОВИДНОСТЬ ($VALlIH (МЕРОПРИЯТИИ))) имеш и значения слотов
(ВРЕМЯ (JDEKAULT (СРЬДА 14.00)-)) (умапчшшемые
(МЕСТО (SDF.1AULT (ЗАЛ ЗАСЕДАНИЙ))) значения насле-
) дуются субфреймами)
(СОБРАНИЕ .38
(РАЗНОВИДНОСТЬ ($VALUE
(ПРИСУТСТВУЮТ
(СОБРАНИЕ)))
(РОНАЛЬД)
(СИНДИ)
(ФРЕД)))
имч фрейма
имена и значения слотов
Наследование значений слотов
Другой важнейшей концепцией формализма фреймов является насле-
наследование. Можно дать указание о том, что если значение слота в одном из
фреймов не задается, то фрейм должен унаследовать умалчиваемое значе-
значение этого слота из фрейма более высокого уровня. Наследование фрейма-
фреймами значений слотов будет осуществляться в том случае, если в фрейме
будет присутствовать слот РАЗНОВИДНОСТЬ, в котором содержится имя
другого фрейма. Например, слоты ВРЕМЯ и МЕСТО фрейма СОБРАНИЕ
будут унаследованы фреймом СОБРАНИЕ-38. Слот РАЗНОВИДНОСТЬ
языка фреймов аналогичен дуге "является" семантической сети в том
смысле, что он представляет отношение включения в класс или отношение
принадлежности к классу.
Оценка формализма фреймов
Фрейм лучше всего трактовать как некоторую разновидность струк-
структур данных. Наследование от фрейма к фрейму реализуется процедурами,
которые осуществляют доступ к конкретным экземплярам структур
данных [36, с. 31]. Если язык фреймов не обеспечивает тот тип вывода,
который нужен программисту, то программист может написать новую
процедуру, обеспечивающую такой вывод. В худшем случае это означает,
что каждый возможный вывод потребуется записывать в явной форме.
Для действительного понимания смысла программы, написанной на языке
фреймов, необходимо соотнести выражения на языке фреймов с проце-
процедурами, реализующими выводы для фреймов. Это может оказаться весьма
сложным, так как процедуры записываются на языке, отличном от языка
фреймов.
266 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Реализация фрейм-программы на Прологе
Нижеследующая Пролог-программа выражает структуру приведен-
приведенного выше примера СОБРАНИЕ.
разновидность (собрание, мероприятие).
разновидность(собрание_38, собрание).
% локальные значения слотов для фрейма СОБРАНИЕ:
собрание (время, 'Среда 14.00').
сопрание(место, 'Зал заседаний').
% локальные значения слотов для фрейма СОБРАНИЕ_38:
собрание „38 (присутствуют, [рональд, синди, фред]). % A)
% правила наследования
собрание_38 (Атрибут, Значение) :- % B) .
разновидность (собрание _38, Фрейм),
Подцель =.. [Фрейм, Атрибут, Значение],
Подцель.
Обратите внимание на то, что и "собрание", и "собрание_38" — это базы
данных, в которых хранятся атрибуты (см. разд. 2.5). База данных "соб-
"собрание" связана с базой данных "собрание_38" при помощи факта «разно-
«разновидность (собрание—38, собрание)». Правило наследования позволяет
"собранию_38" наследовать любые значения атрибутов от "собрания".
Если запросить время проведения "собрания_38":
; ?- собрание38 (время, X).
Х ='Среда 14.00'
то ответ будет получен по факту "собрание" при помощи правила наследо-
наследования.
Факты, противоречащие друг другу
Представьте себе, что сперва планировалось провести "собрание...38"
в принятое по умолчанию время (Среда, 14.00), но потом по какой-то
причине понадобилось его перенести. Посмотрим, что получится, если
в базу данных "собрание _38" добавить атрибут "время", противореча-
противоречащий уже имеющемуся атрибуту.
собрание_38 (время, 'Четверг 9.00').
Теперь в слоте "время" фрейма "собрание_38" будут находиться два
6.3. ФРЕЙМЫ 267
значения — локальное значение и унаследованное значение:
! ?— собрание _38 (время, X).
X = ' Четверг 9.00';
X = 'Среда 14.00';
нет
Здесь трудность состоит в том, что "собрание-38" должно опигывать
реальное собрание, которое может быть проведено только один раз. Ины-
Иными словами, отношение между собранием и временем его проведения
должно регулироваться ограничением вида один-к-одному, обеспечиваю-
обеспечивающем целостность отношения. Однако в данной версии программы запрос
ырабатывает два значения времени проведения собрания. Значение «Чет-
ерг 9.00» должно перекрывать умалчиваемое значение «Среда 14.00»,
ак что запрос, подобный приведенному выше, должен вырабатывать
Только значение «Четверг 9.00».
Запрет наследования
Проблема решается прн помоши приводимой ниже программы.
едикат "сократить" в нервом правиле "собрание_38" гарантирует
Ь, что если у фрейма "собрание—38" будет иметься локальное значе-
Йе слота, то этот фрейм не сможе! унаследовать другое значение того
t самого слота oi фрейма "собрание".
р:пновиднопь (собрание, мероприятие),
разновидность (с_38, собрание).
% значения слотов фрейма "собрание":
собрание (время, 'Среда 14.00').
собрание (место,'Зал заседаний').
% локальное правило
собрание_38 (Атрибут, Значение) : —
с—38 (Атрибут, Значение),!.
7с правило наследования
собрание_38 (Атрибут. Значение) :—
разновидность (с__38, Фрейм),
Подцель =. . [Фрейм, Атрибут, 3Ha4eiffleJ,
Подцель.
% значения слотов, локальные по отношению к фрейму
% "собрание_38":
С—38(присутствуют, [рональд, синди, фред]).
I с-_38 (время, 'Четверг 9.00').
268 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Все атрибуты, являющиеся локальными для фрейма "собрание—38",
теперь хранятся в базе данных "с-38". Первое правило "собрание_38"
проверяет, имеется ли в базе данных "с—38" фраза с требуемым атри-
атрибутом. Если имеется, то возвращается нужное значение, а предикат "сок-
"сократить" предотвращает дальнейшую выдачу ответов. Если такой фразы
нет в базе данных "с—38", то второе правило "собрание_38" ищет тре-
требуемый атрибут в базе данных "собрание". Теперь запрос о времени
проведения собрания выдает единственный ответ:
| ?- собрание_38 (время, X).
X = ' Четверг 9.00'; % по "cl.38"
нет
; ?- собрание_38 (место, X).
X = 'Зал заседаний'; _ % по "собрание ,138"
нет
6.4. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
Объекты и сообщения
В языке объектно-ориентированного программирования, таком как
Смолток-80, фундаментальной вычислительной сущностью является
объект. Единственный способ выполнить вычисление заключается в том,
чтобы послать объекту сообщение. Объекты организуются в классы.
Объект является конкретным экземпляром, принадлежащим к классу.
В определении класса задается структура его объектов. Типичная прог-
программа организована в виде иерархии классов. Класс аналогичен струк-
структуре данных процедурного языка, а объект — конкретному экземпляру
структуры данных (т.е. переменной).
Определение класса
В определение класса могут входить четыре вида компонент:
1) сообщения (команды для вычислений), воспринимаемые всеми
конкретными экземплярами, принадлежащими к классу;
2) методы (присоединенные процедуры), общие для всех объектов
определяемого класса;
3) переменные классов, значения которых являются общими для всех
объектов заданного класса, и
4) переменные конкретных экземпляров (аналоги "слотов" в фор-
формализме фреймов), значения которых уникальны для каждого конкрет-
конкретного объекта.
6.4. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
269
. Наследование
Множество сообщений, воспринимаем^!* объектом, определяет его
интерфейс (т.е. все возможные способы обращения к этому объекту).
Для каждого сообщения имеется соответствующий метод (т.е. процеду-
процедура), выполняющий вычисления, необходимые для ответа на сообщение.
Сообщения и методы, используемые для выработки ответов на них, на-
наследуются от класса к классу следующим образом. Если посылается со-
сообщение конкретному экземпляру, принадлежащему к некоторому клас-
классу и оно не определено для этого класса, то сообщение передается супер-
суперклассу данного класса (т.е. классу, находящемуся в иерархии надданным).
Тем самым класс наследует все сообщения, определенные в его супер-
суперклассе или выше. Если унаследованное сообщение переопределяется ч
классе, то локальное определение перекрывает унаследованное для этого
класса определение.
На рис. 6.4 показана иерархия классов программы, несущей инфор-
информацию о видах птиц.
Если объекту "ральф" посылается сообщение, в котором спраши-
спрашивается о способе передвижения, то это сообщение обрабатывается мето-
КЛАСС «ПТИЦЫ»
Метод класса:
на вопрос о способе
передвижения
ответить «полет»
Суперкласс
КЛАСС «КАНАРЕИКИ»
Метод класса:
на вопрос о цвете
ответить «желтый»
КЛАСС «ПИНГВИНЫ»
Метод класса:
на вопрос о способе
передвижения
Ответить «хождение
вразвалочку »
Конкретный
экземпляр
Конкретный
экземпляр
Объект «твити»
С Объект «раль(р» j
Рис. 6.4
270 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
дом класса ПИНГВИНЫ и выдается ответ «хождение вразвалочку)).
Но если послать то же самое сообщение объекту "твити", то мы увидим,
что в классе КАНАРЕЙКИ отсутствует обработка этого сообщения. По-
Поэтому данное сообщение пересылается в класс ПТИЦЫ, являющийся
суперклассом класса КАНАРЕЙКИ. Сообщение обрабатывается мето-
методом класса ПТИЦЫ и выдается ответ «полет».
Формализм объектно-ориентированного программирования можно
одновременно трактовать и как обобщение понятия абстрактных типов
данных, и как уточнение формализма фреймов. Стоит подробно рассмот-
рассмотреть обе точки зрения.
Объектно-ориентированное программирование
в терминах абстрактных типов данных
В большинстве языков программирования переменные характери-
характеризуются типом. Тип переменной задает область значений, которыми она
может обладать, а также определяет множество операций, которые мож-
можно выполнять над ней. В языке имеется множество так называемых при-
примитивных типов данных, таких как целые числа, числа с плавающей точ-
точкой, символы и т.д. С каждым типом связаны операции, предназначенные
для выполнения действий с переменными этого типа - для сложения,
вычитания и т.п. Тот факт, что необходимо объявлять тип переменных,
ограничивает возможности программиста по использованию перемен-
переменной. В языках со строгой типизацией компилятор выдаст диагностиче-
диагностическое сообщение, если операция, предназначенная для переменных одного
типа, булет применена по отношению к переменной другого типа.
Абстрактные типы данных
Во многих языках разрешается определять сложные типы данных на
основе примитивных типов. Примерами сложных типов данных могут
служить структуры языка Си и записи языка Паскаль. Язык как тако-
таковой не предоставляет операций для выполнения действий над перемен-
переменными, принадлежащими к сложным типам данных, но позволяет про-
программисту определять процедуры, которые могут выполнять действия
над таким переменными. В этом смысле понятие процедуры является
обобщением понятия операция. Комбинация из сложного типа данных
и всех процедур, которые могут выполнять действия над переменными
этого типа, называется абстрактным типом данных. Примером абстракт-
абстрактного типа данных, реализованного в языке Си, служит массив структур,
используемый для хранения записей базы данных, совместно с процеду-
процедурами поиска, добавления, удаления и изменения элементов этого массива.
Понятие класса в объектно-ориентированном формализме можно
рассматривать как абстрактный тип данных. Объект — это конкретный
экземпляр (т.е. переменная), принадлежащий к сложному типу данных.
6.5. МЕХАНИЗМ НАСЛЕДОВАНИЯ В ПРОЛОГЕ 271
а множество сообщений, воспринимаемых объектом, выступает в роли
операций, применимых к Переменным этого типа.
Если посмотреть на приведенный выше пример с птицами с позиций
абстрактных типов данных, то класс ПТИЦЫ будет абстрактным типом
данных, а метод, отвечающий на вопрос о способе передвижения, будет
одной из операций для этого типа. Этой операцией могут воспользоваться
любые другие абстрактные типы данных, стоящие в иерархии под клас-
классом ПТИЦЫ, т.е. типы КАНАРЕЙКИ, ПИНГВИНЫ и т.д. Как можно
заметить, у типа ПИНГВИНЫ имеется своя локальная операция, пред-
предназначенная для выдачи ответа на вопрос о способе передвижения.
Объектио-орнентированное программирование
в терминах формализма фреймов
Объектно-ориентированный формализм можно также трактовать
и как уточнение формализма фреймов. В формализме фреймов не де-
делается различия между видом отношений класс/подкласс и видом отно-
отношений класс/конкретный экземпляр (т.е. одно и то же отношение РАЗ-
РАЗНОВИДНОСТЬ может существовать и как отношение между двумя клас-
классами, и как отношение между классом и конкретным экземпляром), в
то время как в объектно-ориентированном формализме эти два вида
отношений являются ортогональными. Скажем, если бы пример с собра-
собранием (см. разд. 6.2) был реализован на языке Смолток, то СОБРАНИЕ
было бы классом, а МЕРОПРИЯТИЕ было бы суперклассом СОБРА-
СОБРАНИЯ, но СОБРАНИЕ.. 38 было бы конкретным экземпляром СОБРАНИЯ.
6.5. МЕХАНИЗМ НАСЛЕДОВАНИЯ В ПРОЛОГЕ
Наследование в других формализмах
Формализм фреймов допускает, чтобы значения слотов фрейма об-
общего вида наследовались конкретным фреймом. Наследование можно
запретить, если ввести значение слота в конкретный фрейм, при этом на-
наследуемое значение слота будет перекрыто. Сходным образом объектно-
орэтентированный формализм допускает, чтобы сообщения (и связанные
с ними методы) общего класса наследовались конкретным классом. На-
Наследование будет отменено, если для конкретного класса будет опреде-
определено сообщение, перекрывающее наследуемое сообщение. Концепция
наследования придает этим формализмам большую выразительную силу
при представлении таксономии знаний и, говоря словами Ковальски,
"...побуждает нас... к рассуждениям путем сравнения новых случаев
с принятыми ранее стереотипами" [58, с. 4].
272 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Наследование в Прологе
До сих пор в данной главе рассматривались неуниверсальные спо-
способы реализации механизма наследования при помощи языка Пролог.
Так, во втором примере с собранием наследование осуществлялось по-
посредством процедуры:
% локальное правило
собрание _38 (Атрибут, Значение) :-
с_38(Атрибут, Значение), !.
% правило наследования
собрание_38 (Атрибут, Значение) :-
разновидность(с_38, Фрейм),
Подцель = . . [Фрейм, Атрибут, Значение],
Подцель.
Такой подход приводит к искаженному отображению структуры
представляемой системы. Ему к тому же свойственны два ограничения:
1) он применим только к базам данных, информация в которых хранится
в виде атрибутов,представленныхвформе ((Фрейм(Атрибут, Значение)));
и 2) применение предиката "сократить" в первом правиле не дает воз-
возможности употребить в правиле "собрание_38" более одного локаль-
локального значения атрибута. Было бы желательным иметь общий механизм
описания наследования в Прологе, свободный от этих ограничений.
Состояния знаний
Согласно Хейесу [40, с. 54-56] наследование можно трактовать как
разновидность вывода, выполняемого между состояниями знаний. Для
того чтобы пояснить, что имеет в виду Хейес, дадим полную интерпре-
интерпретацию символических обозначений для примера с собранием. Предполо-
Предположим, что еженедельные собрания, в которых участвуют Рональд, Синди
и Фред, проводятся регулярно по средам в 14.00. Можно сказать, что
среда 14.00 — это умалчиваемое время проведения еженедельных соб-
собраний, в которых принимают участие эти лица. Когда первоначально пла-
планировалось еженедельное собрание "собрание_38", то все его участники
предполагали, что оно будет проведено в обычное время. В среду утром,
однако, Фред узнает, что он должен уехать после обеда, и поэтому про-
просит перенести "собрание_38". Участники собрания соглашаются пере-
перенести его на четверг на 9.00. Перенос срока проведения собрания привел
к изменению состояния знаний этих людей о еженедельном собрании.
В новом состоянии знаний умалчиваемое время проведения собрания
перекрывается новым значением времени.
При представлении этой ситуации с помощью фреймов состояния
знаний о ней (до и после действий Фреда) задаются в неявном виде. Пред-
6.5. МЕХАНИЗМ НАСЛЕДОВАНИЯ В ПРОЛОГЕ 273
ставление ситуации станет более четким, если состояния знаний будут
выражены в явной форме. Этого можно будет добиться, если присвоить
имена состояниям знаний и добавить в каЗкдое отношение, входящее в
представление, дополнительный параметр, который будет связывать от-
отношение с тем состоянием, в котором это отношение имеет место. Отно-
Отношение между состояниями знаний также должно быть выражено явно.
Тогда наследование информации от общего состояния знаний к конк-
конкретному состоянию знаний можно будет реализовать при помощи про-
процедуры общего назначения.
В оставшейся части данной главы рассматриваются реализация и
рименение универсального механизма наследования, написанного на
зыке Пролог. Механизм основывается на явных ссылках к состояниям
жаний. Он дает возможность лргмраммисту представлять структуру си-
синем, в которых существует наследование (например, "собрание''), без
«еобходимости использовать побочные эффекты управления во фра-
iax, ориентированных на конкретное применение. Данный механизм яв-
яется расширением обрабатывающей структуры Пролога, которое
холжно усилить выразительную силу языка.
Обзор механизма наследования
Механизм наследования — это метод представления многих состоя-
состояний знаний, при котором конкретное состояние может наследовать ин-
информацию от общего состояния. Фраза ставится в соответствие состоя-
шю путем добавления имени состояния в заголовок фразы (в виде пер-
юго ее аргумента); все остальные аргументы не изменятся. Отношение
между общим и конкретным состояниями записывается в виде факта
"порождение/2". Наследование фраз от состояния к состоянию реали-
реализуется процедурой "послать". С декларативных позиций процедуру "пос-
1ать" можно трактовать как отношение, существующее между состоя-
шем знаний и запросом, если можно доказать истинность запроса по
фразам, связанным с данным состоянием.
Главной аналитической задачей при использовании механизма насле-
цования является установление иерархии состояний знаний. Взаимосвязь
состояний можно рассматривать как дерево, в котором каждое состоя-
Ше представляется узлом. Пусть имеются два состояния, А и Б. Если
состояние Б — это узел дерева, порожденный состоянием А, то Б унас-
•едует все фразы, связанные с А, за исключением тех, которые явно
Опровергаются в Б.
Предположим, что самым верхним состоянием конкретного дерева
•вляется состояние «служащие». Оно содержит информацию, в целом
•рименимую по отношению ко всем служащим, такую как места распо-
'ожения отделов, имена менеджеров отделов и т.д. У состояния «слу-
274
ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
жащие» есть два порожденных им состояния - «служащие, получающие
оклад» и «служащие, работающие по контракту». Состояние «служа-
«служащие, получающие оклад» содержит базу данных, в которой хранятся
сведения об именах служащих, получающих оклад, и иную информацию,
например данные о виде налоговой ведомости, которую эти служащие
получают в конце года. Состояние «служащие, работающие по контрак-
контракту» содержит базу данных со сведениями об именах служащих, рабо-
работающих но контракту, и иную относящуюся к этим служащим инфор-
информацию. Данное дерево состояний изображено на рис. 6.5:
СЛУЖАЩИЕ
Менеджеры
Места расположе-
расположения отделов
порождение
СЛУЖАЩИЕ, РАБОТАЮЩИЕ
ПО КОНТРАКТУ
Служащие
Агентства
Налоговые ведомости
СЛУЖАЩИЕ,
ПОЛУЧАЮЩИЕ ОКЛАД
Служащие
Налоговые ведомости
Рис. 6.5
Аналогия с объектно-ориентированным программированием
Если воспользоваться терминологией объектно-ориентированного прог-
программирования, то информация извлекается из состояния путем посыл-
посылки сообщения этому состоянию. Если состоянию «служащие, работаю-
работающие по контракту» будет послано сообщение, требующее предоставить
информацию о налоговых ведомостях, то ответ на сообщение придет не-
непосредственно от этого состояния. Но если в сообщении, посланном к
состоянию «служащие, работающие по контракту», будет затребована
информация о менеджере отдела, то это состояние не сможет дать ответ
и передаст сообщение порождающему состоянию, т.е. состоянию «слу-
«служащие». Ответ на сообщение выдаст состояние « служащие».
6.5. МЕХАНИЗМ НАСЛЕДОВАНИЯ В ПРОЛОГЕ 275
Ответы, вырабатываемые процедурой "послать "
Процедура "послать" применяется для~ извлечения информации из
состояния. Механизм наследования не накладывает никаких своих ог-
ограничений, обеспечивающих целостность, поэтому запрос к процедуре
"послать" может выдать множество ответов, получаемых более чем из
одного состояния. Предположим, например, что с состоянием «служа-
«служащие, получающие оклад» связана база данных, содержащая сведения
о собраниях отдела, в которых обязаны участвовать только служащие,
получающие оклад. С состоянием «служащие» связана база данных со
сведениями о собраниях, на которых должны присутствовать все слу-
служащие отдела. Запрос о собраниях отдела, адресованный к состоянию
«служащие, получающие оклад)), вначале выдаст информацию о тех
избраниях отдела, в которых должны участвовать только служащие, по-
поручающие оклад, а затем — сведения о собраниях отдела, на которых
необходимо присутствовать всем служащим.
Создание дерева состояний
Отношение двух состояний описывается в базе данных "порождение".
Для того чтобы реализовать приведенный выше пример в виде программы,
нужно, чтобы один факт "порождение" свидетельствовал о том, что
состояние «служащие, получающие оклад)) порождено состоянием «слу-
«служащие», а другой факт говорил о том, что и состояние «служащие, ра-
работающие по контракту)) является порождением состояния «служащие)).
Связь фразы Пролог-программы с определенным состоянием устанав-
устанавливается благодаря введению дополнительного аргумента, содержащего
имя состояния.
Приведем версию программы для примера со служащими.
% дерево состояний:
порождение (на—окладе, служащие).
порождение (по-контракту, служащие).
% фразы, связанные с состоянием "служащие":
% Состояние Отд Расположение
расположение_отдела(служащие, 100, 'Флигель 2-й этаж ).
расположение_отдела(служащие, 200, 'Здание 4073').
% Состояние Отд Менеджер
менеджер_отдела (служащие, 100, смит).
менеджер_отдела(служащие, 200, родригес).
% собрание всех служащих отдела 100:
собрание—отдела (служащие, 100, 'Вт 22.01 Комната 235').
276, ГЛ. 6. ПРЕДСТАВЛЕНИЕ аНАНИЙ
% фразы, связанные с состоянием "на_окладе":
% Состояние Имя Отд Оклад
служ(на_окладе, хове, 100, 55000).
служ(на—окладе, листвиски, 100, 40000).
служ(на_окладе, аптон, 200, 35000).
% Состояние Форма
налогов—Ведомость (на-окладе, 2).
% собрание только для служащих отдела 100, получающих
% оклад:
собрание__отдела(на_окладе, 100,'Пн21.01 Комната 201').
% фразы, связанные только с состоянием "по_контракту":
% Состояние Имя Отд Оклад
служ (по—контракт у, льюис, 100, неприменим).
служ (по-контракту, бертоли, 200, неприменим). ¦ -
% Состояние Форма
налогов—ведомость (по_контракту, 1099).
Процедура "послать"
Наследование фраз от состояния к порожденным им состояниям реа-
реализуется процедурой "послать". У этой процедуры два аргумента — имя
состояния, к которому обращен запрос, и Пролог-запрос, в котором от-
отсутствует аргумент, обозначающий имя состояния. Нижеследующий вы-
вызов процедуры "послать" запрашивает номер формы налоговой ведо-
ведомости, которую следует выдать служащим, работающим по контракту:
1 ?— послать (по „контракту, налогов— ведомость (Форма)).
Форма = 1099 ;
нет
Обратите внимание на то, что процедура "послать" смогла найти только
один ответ на запрос «налогов—ведомость (Форма))). В следующем вы-
вызове процедуры "послать" задается вопрос о менеджере служащих, ра-
работающих в отделе 100 по контракту. Из ответа видно, что состояние
«по—контракту» наследует фразы от состояния « служащие».
! ?— послать (по—контракту, менеджер— отделаA00, Кто)).
Кто = смит ;
нет
Переадресация запроса
Если процедура "послать" не может решить запрос в соответствии
с фразами заданного состояния, она переадресует этот запрос к порож- ,
дающему состоянию. Если запрос потерпит повторную неудачу в порож- .>
6.5. МЕХАНИЗМ НАСЛЕДОВАНИЯ В ПРОЛОГЕ 277
даюшем состоянии, то процедура "послать" ^переадресует его к порож-
порождающему состоянию еще более высокого уровня. Этот процесс может
продолжаться до тех пор, пока не будет достигнуто порождающее со-
состояние самого высокого уровня.
Нижеследующий запрос спрашивает о собраниях, в которых должны
принять участие все служащие отдела 100, получающие оклад. Данный
Пример показывает, что процедура "послать" может вырабатывать отве-
ы на основании информации, получаемой более чем из одного состояния.
J ?— послать (на-окладе, собрание—отдела A00, М)).
М = 'Пн 21.01 Комната 201' ; % по состоянию "на__окладе"
М = 'Вт 22.01 Комната 235' ; % по состоянию "служащие"
нет
Опровержение фразы
Предполои&м1, что компания в качестве поспешной дискримина-
анной меры решает переместить в подвальное помещение флигеля всех
гжащих отдела 100, работающих по контракту. Это равнозначно из-
рению структуры системы, что потребует надлежащего изменения
рсания системы. Такое изменение можно осуществить при помощи
груктивного перекодирования соответствующих баз данных. Но есть
другой способ внесения изменений, при котором существующие базы
иных будут затронуты в минимальной мере. Для этого нужно добавить
(состоянию «по—контракту)) новый факт «расположение—отдела)) и
эвергнуть старый факт:
расположение_отдела(по—контракту, 100, 'Подвал флигеля'),
опровергну ть (по—контракту,
расположение-отдела (служащие, 100, 'Флигель 2-й этаж')).
Состояние «по-контракту» — это состояние, для которого осуще-
осуществляется опровержение, а фраза «расположение—отдела (служащие, 100,
Флигель 2-й этаж'))) — это опровергаемая фраза. После того как в прог-
программу будут добавлены приведенные выше фразы, при просьбе выдать
место расположения отдела 100, адресованной к состоянию «по_конт-
ракту», будет выводиться новое значение:
, ?— послать(по_контракту, расположение—отделаA00, Р)).
Р = 'Подвал флигеля ;
лет
' но требованию выдать ту же самую информацию, адресованному к
278 П. 6. НГТ ОСТАВЛЕНИЕ ЗНАНИЙ
состоянию «служащие)), все еще будег вырчбатьп;пься старое значение:
! ?— послать (служащие, расположение- отдела A00, Р)).
Р = Флигель 2-й этаж/ ,
нет
Если фраза опровергнута для конкретного состояния, то она боль-
больше не будет наследоваться ни этим состоянием, ни любыми другими по-
порожденными им состояниями Если же к состоянию была бы добавлена
новая фраза, то она стала бы наследоваться всеми ею порожденными
состояниями. Описанное употребление факта "опровергнуть" значитель-
значительно облегчает сопровождение программы.
Концепции механизма наследования
Механизм наследования базируется на следующих ключевых кон-
концепциях:
1) иерархия состояний знаний;
2) наследование фраз от состояния к состоянию, и
3) отмена наследования фразы путем ее опровержения.
Концепции формализма фреймов так соответствуют приведенным
выше концепциям:
- фрейм соответствует состоянию знаний;
- слот соответствует фразе, относящейся к состоянию знаний;
- наследование значений слотов от фрейма к фрейму соответствует
наследованию фраз от состояния к состоянию и.
- способность локального значения слота перекрывать наследуемое
значение слота соответствует возможности опровергнуть унасле-
унаследованную фразу и заменить ее новой фразой
Концепции объектно-ориентированного формализма так соответ-
соответствуют концепциям механизма наследования:
- класс соответствует состоянию знаний;
- метод соответствует фразе, относящейся к сосюянию -чшний:
- объект соответствует фразе, относящейся к состоянию зияний;
- наследование методов от класса к классу соответствует наследо-
наследованию фраз от состояния к состоянию;
- способность локального метода перекрывать унаследованный ме-
метод соответствует возможности опровергнуть унаследованную
фразу и заменить ее новой фразой.
Пример с собранием
Для разъяснения данных положений целесообразно посмотреть, как
можно воспользоваться механизмом наследования дпя реализации прос-
простых примеров, приведенных ранее в данной главе. Ниже дается версия
программы для примера с собранием. У состояния «собрание» имеются
6.5. МЕХАНИЗМ НАСЛЕДОВАНИЯ В ПРОЛОГЕ 279
два потомка (т.е. порожденных состояния): «собрание_38>>, наследую-
наследующее от состояния «собрание» умалчиваемое значение времени проведе-
проведения собрания, и «собрание-39>>, в котором задается свое собственное
время.
% дерево состояний:
порождение (собрание, мероприятие).
порождение(собрание_38, собрание),
порождение (собрание _39, собрание).
% фразы, относящиеся к состоянию "собрание":
время (собрание, 'Среда 14.00').
место (собрание, 'Зал заседаний').
'' фразы, относящиеся к состоянию "собрание_38":
присутствуют(собрание_38, [рональд, синди, фред]).
% фразы, относящиеся к состоянию "собрание—39":
тема (собрание _39,'версия 3.01),
присутствуют (собрание—39, [марта, рональд, синди]).
опровергнуть (собрание—39, время (со бра ше. -)).
время (собрание—39, 'Четверг 9.00').
братите внимание на то, что значение времени, наследуемое из состоя-
состоялся ((собрание)), опровергается в состоянии «собрание_39>>. Это опро-
!ржение предохраняет состояние «собрание—39>> от появления двух
ротиворечащих друг другу значений времени проведения собрания. За-
етые также, что все приведенные фразы свободны от побочных эффек-
)В управления.
Каким образом можно было бы употребить процедуру "послать"
для того, чтобы узнать время проведения «собрания—39>>? Не могли
ли бы Вы написать правило, аргументом которого служит название соб-
собрания и которое выдает на печать всю имеющуюся информацию об этом
собрании?
Пример с птицами
Приведем версию программы, отражающую структуру примера с
птицами.
% дерево состояний:
порождение (канарейки, птицы).
порождение (пингвины, птицы).
% фразы, относящиеся к состоянию "птицы":
способ—передвижения (птицы, полет).
% фразы, относящиеся к состоянию "канарейки":
цвет (канарейки, желтый).
280 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
% база данных, описывающая отдельных канареек:
индивидуум (канарейки, твити).
индивидуум (канарейки, стив).
% фразы, относящиеся к состоянию "пингвины":
цвет (пингвины, 'черный и белый').
опровергнуть (пингвины, способ—передвижения (птицы, _)).
способ—передвижения (пингвины, ходьба_вразвалочку).
% база данных, описывающая отдельных пингвинов:
индивидуум (пингвины, ральф).
Нижеследующий запрос найдет всех птиц, способ передвижения которых —
« ходьба вразвалочку»;
! ?— порождение(Поюмок, птицы),
послать (Потомок, способ—передвижения (ходьба—вразвалочку)),
послать(Потомок, индивидуум (И)).
Потомок - пингвины
И = ральф;
нет
Подцель "порождение" генерирует состояние-кандидат, являющееся
потомком состояния «птицы». Вторая подцель проверяет, является ли
способ передвижения для состояния-кандидата ходьбой вразвалочку.
Если это так, то третья подцель генерирует всех индивидуумов, связан-
связанных с данным состоянием. Приведенный запрос может производить поиск
с возвратом, проходя через все состояния-потомки, порожденные со-
состоянием «птицы».
Реализация процедуры "послать"
Процедура послать реализуется следующим образом.
% послать: адресовать запрос к состоянию
послать (Состояние, Q) :—
Q =.. [X 1 Y], % представить запрос в виде списка
послатьО(Состояние, Состояние, [X1Y]).
% Q состояние — это состояние, к которому был адресован
% исходный запрос. '
послатьО(Qсостояние, Состояние, [X ! Y]):— "''
Q =. . [X, Состояние ! Y], % синтезировать запрос к
% состоянию ¦
Q, % выполнить запрос
not (опровергнут(Bсостояние, Состояние, Q)).
6.5. МЕХАНИЗМ НАСЛЕДОВАНИЯ В ПРОЛОГЕ 281
послать0(Cсостояние, Состояние, [X ,' Y]):—
% сгенерировать порождающее состояние:
порождение (Состояние, ПорождСост),
% попробовать выполнить запрос к порождающему
% состоянию:
послатьО(Осостояние, ПорождСост, [X ' YJ).
% считать запрос Q оировергн)тым, если он опровергается
% дня состояния равного или более высокого, чем то состоя-
% ние, к которому был обращен исходный запрос,
опровергнут(Qc-остояние, Состояние, Q) :—
. опровергнуть ((^состояние, Q),
' % состояние Мсостояние, где запрос Q опровергается,
Ч должно быть более высоким или равным состоянию запроса:
больше—или—равно (Ысостояние, (^состояние),
7<j но меньше или равно Состоянию, к которому был
% адресован запрос Q:
больше_или—равно(Состояние, Мсостояние),!.
больше._или-равно(Х, X):— !.
больше_или_равно (X, Y) :—
порождение (Y, Z),
больше „или _.равно (X, Z).
|Правило "опровергнут" можно прочесть так:
Фраза опровергается
с точки зрения имеющегося запроса, если
она опровергается в некотором состоянии Мсостояние,
более высоком или равном тому состоянию, в которое
фраза была первоначально добавлена,
и менее высоком шш равном состоянию, к которому
запрос был адресован.
Состояние J (где фраза добавлена)
^состояние j (где фраза опровергается)
С ^состояние J (к которому адресован
v • запрос)
Рис. 6.6
282 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Отношение между переменными «Состояние», «О_состояние» и
«NcocioflHHe» в правиле "опровергнут" показано на рис. 6.6.
Алгоритм работы процедуры "послать"
Процедура "послать" берет запрос Q, превращает его в список, а за-
затем вызывает процедуру "послатьО". Первый аргумент процедуры "пос-
латьО" — это название состояния, к которому был обращен исходный
запрос. Он остается неизменным при всех последующих рекурсивных
вызовах процедуры "послатьО". Вторым аргументом процедуры "послатьО"
является имя того состояния, где будет осуществляться попытка выпол-
выполнения запроса. При первом вызове процедуры "послатьО" второй аргу-
аргумент будет равен первому, но при каждом последующем рекурсивном
обращении он будет становиться именем родителя предыдущего состояния.
Процедура "послатьО" синтезирует запрос Q по своему третьему ар-
аргументу, включая в запрос в качестве первого аргумента имя текущего
состояния. Затем запрос Q выполняется и, если он оказывается уепеш-
ным, процедура "послатьО" осуществляет проверку, чюбы убедиться,
что выработанный ответ не был опровергнут где-либо между состоянием
запроса и текущим состоянием. Если пользователь затребует другой от-
ответ, процедура "послатьО" проведет поиск с возвратом с целью нахожде-
нахождения нового ответа в том же самом состоянии, где был найден предыду-
предыдущий ответ. Если для этого состояния больше не будет ответов, то про-
процедура "послатьО" выполнит рекурсивные действия и приступит к поиску
ответов в состоянии, являющемся родителем данного состояния. Этот
процесс продолжится вплоть до достижения самого верхнего состояния.
6.6. ПРОГРАММА, ВЫПОЛНЯЮЩАЯ ЗАПРОСЫ К БАЗЕ ДАННЫХ
Теперь рассмотрим некоторые применения механизма наследования.
Первым из них будет таблично-управляемая программа, выполняющая
запросы к базе данных. Эта программа предоставляет пользователю возмож-
возможность последовательно уточнять запросы. Описьшаемая данной программой
система — это ведомость запасов бумаги полиграфической компании.
Состояния как виртуальные базы данных
В начале сеанса работы пользователя с программой, выполняющей
запросы к базе данных со сведениями о бумаге, база данных ассоцииру-
ассоциируется с состоянием, названным «бумага». Когда пользователь вводит
запрос, требуя выдачи сведений об определенных позициях ведомости
с информацией о бумаге, удовлетворяющих заданным критериям, то
автоматически вводится новое состояние, являющееся потомком состоя-
состояния «бумага». С новым состоянием связываются критерии выбора, вве-
введенные пользователем. Новое состояние выступает в роли виртуальной
базы данных, подвергая исходную базу данных "фильтрации" в соот-
6.6. ПРОГРАММА, ВЫПОЛНЯЮЩАЯ ЗАПРОСЫ К БАЗЕ ДАННЫХ
283
БУМАГА
Критерии выбора,
отсутствуют
порождение
ветствии с заданными критериями выбора. Когда к новому состоянию
посылается запрос об определенных позициях ведомое ш со сведениями о
бумаге, то выдается информация только о техлтозициях, которые удовлет-
удовлетворяют критериям выбора. Это станет более ясно, если рассмотреть пример.
Пусть в самом верхнем состоянии (т.е. в состоянии «бумага») име-
имеются позиции базы данных с цветами голубой, красный, белый и беже-
ьый. Пользователь нише* запрос, в котором указывает, что хочет про-
просмотреть сведения юлько о бумаге красного UBcia. В результате этого
запроса порождается состояние-потомок состояния «бумага», назван-
названное, к примеру, «красная_бумага». Новое состояние «красная__бума-
ia» содержит критерий выбора, согласно которому атрибут цвета дол-
жен име!ь значение «красный». Эта ситуация показана на рис. 6.7:
f Ьиш пользователь захочет про-
|емогре1ь позиции ведомости, выда-
выдавая запрос к состоянию «бумага»,
ш на иеча1ь будут выведены все по-
позиции базы данных. Но если запрос
будет обращен к сосюянию «крас-
ная_6умага>л го будут выведены
юлько сведения о бумаге красного
цвета.
Предположим, что пользователь
адресует запрос к состоянию «крас-
ная_бумага», указывая при этом на
необходимость получения сведений
юлько о бумаге с гладкой поверх-
поверхностью. В результате данного запроса
образуется состояние «гладкая._крас-
ная_6умага», порождаемое состоя-
состоянием «красная_бумага». Состояние
«гладкая _красная_бумага» содер-
содержит критерий выбора, в соответствии
с которым атрибут, характеризую-
характеризующий поверхность бумаги, должен р и с 6 7
иметь значение «гладкая». Это новое
состояние наследует все критерии выбора своих состояний-предков, так
что если пользователь захочет просмотреть позиции ведомости, обратив-
обратившись к состоянию «гладкая_красная_бумага», то на печать будут выданы
сведения только о гладкой красной бумаге.
Состояния образуют "историю" сеанса работы
Каждое состояние ограничивает базу данных, связанную со своим
родителем, в соответствии с критериями выбора состояния. После того
КРАСНАЯ БУМАГА
Критерии выбора'.
ц,вег=красный
порождение
ГЛАДКАЯ КРАСНАЯ БУМАГА
Критерии выбора:
поверх ность= гладкая
284
ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
как пользователь введет несколько запросов во время сеанса работы с
программой, дерево образованных состояний будет отражать, если так
можно выразиться, "историю" сеанса. Процедура "отобразитьсостоя-
ния" показывает все существующие состояния, а процедура "характер"
отображает все критерии выбора, связанные с заданным состоянием. Эти
процедуры облегчают пользователю написание нового запроса, позволяю-
позволяющего сузить множество ответов предыдущего запроса.
Использование процедуры "з"
Интерфейс этой программы является таблично-управляемым. Поль-
Пользователь опрашивает базу данных при помощи процедуры "з". У процеду-
процедуры "з" имеется два аргумента: имя существующего состояния и имя со-
сшяиия, которое следует образовать в качестве потомка текущего со-
состояния. Процедура "з" выводит таблицу, состоящую из имен всех атри-
атрибутов базы данных., в которой хранятся сведения о бумаге. Если для
атрибута уже установлен критерий выбора в существующем состоянии,
то этот критерий автоматически печатается в надлежащем слоте таблицы.
Если критерий выбора для атрибута не был установлен, то ничего не пе-
печатается, и пользователь может ввести этот критерий. Если же пользо-
пользователь вместо ввода критерия нажмет клавишу возврата каретки, то по
отношению к данному атрибуту не будут применяться критерии выбора.
База данных со сведениями о бумаге
В базе данных со сведениями о бумаге имеется пять атрибутов, опи-
описывающих марку, вес, цвет, поверхность бумаги и ее тип (указывается,
поступает ли бумага в виде листов или в виде рулонов). Вот эта база
данных:
% Состояние Тип Марка
вед_бум (бумага, листы, непрозрачная,
вед_бум (бумага, листы, непрозрачная,
вед_бум (бумага, листы, индексная,
вед_бум(бумага, листы, непрозрачная,
вед_бум (бумага, рулоны, непрозрачная,
вед_бум (бумага, рулоны, индексная,
вед_бум (бумага, рулоны, непрозрачная,
вед_бум (бумага, рулоны, офсетная,
Процедура "отобразить" выводит все позиции ведомости, связанные
с нужным состоянием. Эта процедура имеет один аргумент — имя со-
состояния.
', ?—отобразить (бумага).
листы непрозрачная 60 гладкая голубой •
листы непрозрачная 45 матовая зеленый к
Вес
60,
45,
50,
70,
100,
70,
ПО,
160,
Поверхн.
гладкая,
матовая,
матовая,
глянцевая,
гладкая,
глянцевая,
гладкая,
глянцевая,
Цвет
голубой)
зеленый)
красный)
белый).
бежевый)
красный)
голубой)
красный)
6.6. ПРОГРАММА, ВЫПОЛНЯЮЩАЯ ЗАПРОСЫ К БАЗЕ ДАННЫХ 285
листы индексная 50 матовая красный
листы непрозрачная 70 глянцевая белый
рулоны непрозрачная ЮОгладкая бежевый
рулоны индексная 70 глянцевая красный "¦
рулоны непрозрачная 1 10 гладкая голубой
рулоны офсетная 160 глянцевая красный
.да
Опрос базы данных (добавление нового состояния)
Для добавления нового состояния с именем « краская_рулоны)) , ко-
которое должно располагаться под состоянием «бумага » и содержать все
позиции ведомости, описывающие красную бумагу в рулонах, пользо-
'ватель должен ввести следующий запрос:
% Существует Новое
\ ?—з (бумага, красная._рулоны).
С состоянием «бумага)) не связано никаких критериев выбора, поэтому
программа подсказывает пользователю, что можно ввести значения всех
пяти атрибутов.
тип? рулоны
марка?
вес?
цвет? красный
поверхность?
Пользователь ввел значение «рулоны» в ответ на подсказку ({тип?}),
значение « красный )> в ответ на подсказку « цвет? » и нажал клавишу
возврата каретки в ответ на остальные сообщения-подсказки. В резуль-
результате данного обращения к процедуре "з" образуется новое состояние
«красная_рулоны » как потомок состояния «бумага)). Пользователь
^может исследовать это состояние при помощи процедур "отобразить"
|и "характер". ..••...¦
\ ', ?-отобразить (красная_рулоны).
бумага рулоны индексная 70 глянцевая красный
бумага рулоны офсетная 160 глянцевая красный
да
| ? - характер (красная_рулоны).
тип: рулоны
марка:
вес-
цвет: красный
поверхность:
да
286 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Добавление состояния « тяжелая-красноя-рулоны »
Предположим, что пользователь опять решил применить процедуру
"з" для поиска позиций ведомости, в которых содержатся сведения о
красной рулонной бумаге веса 160. При этом будет образовано новое
состояние «тяжелая„красная_рулоны >>, являющееся потомком по-
порождающего состояния « красная^рулоны ».
%
| ?— з (красная_рулоны, тяжелая_красная_рулоны) .
тип? рулоны
. марка?
вес? 160
цвет? красный
поверхность?
Поскольку состояние «тяжелая_красная_рулоны» наследует все
значения атрибутов, установленные для состояния «красная^рулоны'» ,
процедура "з" не запрашивает у пользователя данных о марке и цвете
бумаги. Вместо этого она отображает значения этих атрибутов, которые
были установлены ранее для состояния «красная_рулоны» . Пользо-
Пользователь ввел значение 160 в ответ на подсказку «вес?» и нажал на кла-
клавишу возврата каретки в ответ на два других сообщения-подсказки.
I ?— отобразить (тяжелая_красная_рулоны).
бумага рулоны офсетная 160 глянцевая красный
да
1 ?- характер
тип:
марка:
вес:
цвет:
поверхность:
(тяжелая_красная_рулоны).
рулоны
160
красный
да
Процедура "отобразитьсостояния'
После того как будет введено большое количество запросов, поль-
пользователь может потерять из виду какие-то из существующих состояний.
Процедура "отобразитьсостояния" показывает все состояния, имеющиеся
Ь.6. ПРОГРАММА, ВЫПОЛНЯЮЩАЯ ЗАПРОСЫ К БАЗЕ ДАННЫХ 287
в данный момент:
| ?— отобразитьсостояния.
бумага
красная-рулоны
тяжелая^ красная ^.рулоны
Полезные свойства программы, выполняющей запросы к базе данных
Первоначальный вариант программы предназначался для оценщиков,
аботающих в типографии. Оценщики часто работают с неполной специфи-
;ацией бумаги, поскольку для выполнения определенного задания может
1ыть пригодным более чем один вид бумаги. Окончательный выбор бу-
бумаги в значительной мере зависит от наличных запасов, так как Дешевле
использовать уже имеющуюся бумагу, чем заказывать новую. Программа,
выполняющая запросы, дает возможность оценщику выявить все типы
бумаги, хранящейся на складе, которые подходят для выполнения кон-
конкретного задания. Версия программы, представленная в настоящей книге,
сильно упрощена по сравнению с исходным вариантом этой программы.
Реализация программы, выполняющей запросы
Программа доступа к ведомости сведений о бумаге реализуется при
помощи связывания множества значений атрибутов с каждым состояни-
состоянием. Если значением атрибута является неконкретизированная перемен-
переменная, то в данном состоянии для этого атрибута отсутствует критерий вы-
выбора. Однако если значением атрибута является атом, то он действует как
критерий выбора для данного состояния. Значения всех атрибутов, связан-
связанные с состоянием "бумага", — это неконкретизированные переменные,
так как данное состояние не обладает критериями выбора. Значения атри-
атрибутов представляются в виде фактов "за" (сокращение от "значение атри-
атрибута") .
% критерии выбора для состояния "бумага":
% Состояние Атрибут Значение
за (бумага, тип, Т).
за (бумага, марка, М).
за (бумага, вес, В),
за (бумага, поверхность, П).
\ за (бумага, цвет, Ц).
Наследование значений атрибутов
Все значения атрибутов состояния "бумага" наследуются его состоя-
состояниями-потомками. Внутри процедур "отобразить", "з" и "характер" отно-
отношение между состоянием и конкретным значением атрибута регулиру-
регулируется ограничением вида один-к-одному, обеспечивающим целостность.
288 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Поэтому после того, как одна из этих процедур найдет значение атрибута,
она не будет искать дополнительные значения этого же самого атрибута.
Следовательно, когда новое значение атрибута добавляется к порожден-
порожденному состоянию, зто значение перекрывает значение атрибута, унаследо-
унаследованное от родительского состояния. >>•
Результат создания состояния « красная-.рулоны »
В результате действий запроса «з(бумага. красная рулоны))'' , при
веденного выше, в текущую программу добавляются следующие фразы:
порождение (красная_рулоны, бумага).
% критерии выбора для состояния "красная_рулоны":
% Состояние Атрибут Значение
за(краснзя__рулэны, nut. рулоны).
за(краоная_рулоны, цвет, красный).
Обратите внимание на то, что значениями атрибутов являются атомы,
а не неконкретизированные переменные, как это имело место выше для
атрибутов состояния «бумага». Значения атрибутов «тип» и «цвет »,
связанные с состоянием « красная_рулоны » , перекрывают значения этих
атрибутов, унаследованные от состояния "бумага". Нижеследующие запро-
запросы к процедуре "послать" показывают, что значения трех других атрибу-
атрибутов состояния «красная_рулоны» все еще наследуются от состояния
« бумага ». .,
! ?— послать (красная_рулоны, за (тип, V)). ¦;
V = рулоны % из состояния "красная_рулоны"
! ?— послать (красная_рулоны, за(марка, V)).
V = -1 % из состояния "бумага"
I ?- послать (красная_рулоны, за (вес, V)).
F=_/ % из состояния "бумага"
] ?—послать (красная_рулоны, за (поверхность. V)).
V = _7 % из состояния "бумага"
I ?— послать (красная_рулоны, за (цвет, V) ).
V = красный % hi состояния "красная_рулоны"
Результат создания состояния « тяжелая ^красная -рулоны ))
В результате приведенного вьпие обращения « з(тяжелая_красная_ру-
лоны, красная _рулоны)» в текущую программу будут добавлены такие
фразы:
порождение (тяжелая__красная_рулоны, красная_рулоны).
за(тяжелая_красная_рулоны, вес, 160).
6.0. ПРОГРАММА, ВЫПОЛНЯЮЩАЯ ЗАПРОСЫ К БАЗЕ ДАННЫХ 289
Состояние <( тяжелая_красная_рулоны» наследует значения атрибутов
типа и цвета от состояния « красная __рулоны », а значения атрибутов
марки и поверхности - от состояния « бумага » , но обладает своим ло-
локальным значением атрибута веса.
Процедура "отобразить"
Аргументом процедуры "отобразить" является имя состояния. Дан-
нан процедура вынодит на печать все позиции ведомости сведений о бу-
бумаге, связанные с этим состоянием.
отобразить (Состояние) : —
% ввести критерии выбора
послатьСС.-. моими., 'за(ши, Т)) ,
носить ^Состояние, за (марка, М)),
послать (Состояние, за (вес, В)),
послать (Состояние, за (поверхность, П)),
послать (Состояние, за (цвет, Ц)),
I
% взять целостный информационный элемент, удовлетворяющий
'7с критериям выбора:
вед _бум (бумага, Т, М, В, П, Ц),
'/{ вывести на печать целостный информационный элемент:
write (T), write (' '),
write (M), write (' '),
write (В), write ('),'• '
write (П), write (' '),
write (Ц), nl,
I % вернуться назад за следующим целостным информационным эле-
| % ментом:
1 fail.
Процедура "отобразить" адресует запросы к заданному состоянию
«Состояние» для получения значений всех атрибутов. Предикат "сокра-
"сократить" гарантирует то, что после получения значений всех пяти атрибутов
процедура не будет пытаться отыскать еще какие-то значения этих атри-
атрибутов. Далее процедура "отобразить" выполняет поиск с возвратом по
базе данных "вед_бум", печатая все целостные информационные эле-
элементы, удовлетворяющие критериям выбора.
Процедура "з"
Программа "з" создает новое состояние, располагаемое под сущест-
существующим состоянием, а затем выдает сообщения-подсказки, в соответ-
соответствии с которыми пользователь может задать критерии выбора для этого
нового состояния.
Ю. Дж. Малпас
290 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
% создать состояние-потомок под существующим состоянием
з(СущСостояние, Потомок) :—
assert (порождение(Потомок, СущСостояние)),
послать (СущСостояние, за (тип, Т) ) ,
заполнить (Потомок, тип, Т),
послать (СущСостояние, за (марка, М)),
заполнить (Ноюмок, марка, М),
послать (СущСостояпие, за (вес, В)),
заполнить (Потомок, вес, В),
послать (СущСостояние, за (поверхность, 11)),
заполнить (Потомок, поверхность, П),
послать (СущСостояние, за (цвет, Ц) ),
заполнить (Потомок, цвет, Ц),!.
заполнить (Состояние, Имяатрибута, Значатрибута) :- % A)
write (Имяатрибута), write (' ? '),
write (' '), ' . .
%если переменная Значатрибута не конкретизирована, то пол учить-
% ее значение у пользователя:
var (Значатрибута),
вводпол я (Значатрибута),
( var (Значатрибута)
% если пользователь ввел значение, добавить его в программу
nonvar (Значатрибута),
assert (за(Состояние, Имяатрибута, Значатрибута))
),!¦
заполнить (_, Имяатрибута, Значатрибута) :— % B)
% если переменная Значатрибута конкретизирована, то вывести на
% печать ее значение,
nonvar (Значатрибута),
write (Значатрибута), и1,!. ¦_,
Обратите внимание на поведение процедуры "заполнить". Первые
подцели правила A) этой процедуры выводят имя атрибута, знак вопро-
вопроса и пробелы для табуляции. Если переменная Значатрибута конкретизи-
конкретизирована, то правило A) потерпит неудачу, и правило B) выведет на пе-
печать значение атрибута. Если переменная Значатрибута не конкретизиро-
конкретизирована, то при обращении к процедуре "вводполя" (см. разд. 3.9) она либо
станет конкретизированной значением, введенным пользователем, либо
останется неконкретизированной, еиги пользователь не будет вводить
значение и нажмет на клавишу возврата каретки. Если пользователь вве-
введет значение атрибута, то в программ/ будет добавлен факт "за", содер-
содержащий это значение.
6.7. ОПИСАНИЕ ИЗМЕНЕНИЙ БАЗЫ ДАННЫХ 291
Процедура "характер"
Процедура "характер" показывает все текущие критерии выбора,
связанные с заданным состоянием.
характер (Мир) :—
послать (Мир, за (тип, Т)),
write ('тип: '),
(nonvar (T), write (T); true), nl,
послать (Мир, за (марка, М) ),
write (' марка: '),
(nonvar (M), write (M); true), nl,
послать (Мир, за (вес, В)),
write ('вес: '),
(nonvar (В), write (В); true), nl,
послать (Мир, за (поверхность, П) ),
write ('поверхность: '),
(nonvar (П), write (П); true), nl,
послать (Мир, за (цвет, Ц)),
write ('цвет: '),
(nonvar (Ц), write (Ц); true), nl,
i
6.7. ОПИСАНИЕ ИЗМЕНЕНИЙ БАЗЫ ДАННЫХ
Динамическая база данных — это база данных, в которую время от
времени требуется вносить изменения, отражающие изменения структу-
структуры описываемой системы. Один из методов реализации динамической
базы данных заключается в деструктивном редактировании базы данных
при необходимости внесения в нее изменений. К сожалению, при деструк-
деструктивном редактировании исчезает возможность возврата к состоянию базы
данных, существовавшему ранее. Это затрудняет анализ изменений базы
данных.
Аксиома фреймов является альтернативной концепцией реализации
динамической базы данных. Если необходимо внести изменение, то ис-
исходная база данных остается неизменной, а записывается собственно из-
изменение. Текущая форма базы данных получается при использовании ее
исходной формы с учетом сделанных изменений. Ниже формулируется
аксиома фреймов, в которой U обозначает любое отношение, а состоя-
состояние S + 1 является результатом выполнения действия А в состоянии S.
10»
292 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Аксиома фреймов
Отношение U будет соблюдаться в состоянии S + 1,
являющемся результатом выполнения действия А в состоянии S,
если U соблюдается в состоянии S,
а А. не влияет на U.
Иными словами, состояние базы данных унаследует каждую фразу
предыдущего состояния, если только эти фразы не были явно изменены
при переходе в данное состояние.
В соответствии с аксиомой фреймов для представления динамической
базы данных можно воспользоваться механизмом наследования. Началь-
Начальное состояние базы данных соответствует самому верхнему узлу дерева
состояний. Каждое новое состояние базы данных вводится как состояние-
потомок предыдущего состояния. Поэтому изменяющаяся база данных
представляется деревом состояний, растущим вниз (рис. 6.8).
После введения нового состояния базы данных, как потомка сущест-
существующего состояния, каждая фраза, связанная с существующим состоя-
состоянием, либо будет унаследована состоянием-потомком (т.е. не изменится),
состояние 1 базы данных)
порождение
состояние 2 базы данных
порождение
Q состояние 3 базы данных
_
Рис. 6.8
либо будет перекрыта новым значением (т.е. изменится), либо будет
опровергнута (т.е. удалена). Помимо этого, в новое состояние могут бы*Ь
введены новые фразы.
Мир кубиков
Мир кубиков — это пример, часто используемый для того, чтобы про-
проиллюстрировать аксиому фреймов. Для точного описания мира кубиков
требуется динамическая база данных, в которой задаются положения ку-
кубиков на крышке стола. Метод, употребляемый для представления мира
6.7. ОПИСАНИЕ ИЗМЕНЕНИЙ БАЗЫ ДАННЫХ 293
кубиков, можно с успехом применить и в других задачах, где требуется
динамическая база данных.
Описываемая версия мира кубиков основывается на базе данных,
состоящей из фактов "на/3", при помощи которых задается положение
кубиков. Факт «Ha(S, А, В)» означает, что в состоянии S кубик А нахо-
находится на верхней части кубика В. Процедура "поместить" позволяет поль-
пользователю перемещать кубики, входящие в мир, на другие места, что со-
соответствует переходам к новым состояниям базы данных "на". Начальное
состояние базы данных "на" носит название ", следующее состояние —
" и т.д.
Характеристики отношения "на"
Отношение "на" - это отношение либо между двумя кубиками в
некотором состоянии, либо между кубиком и столом. Согласно опреде-
определению данное отношение несимметрично, нерефлексивно и нетраизитив-
но. Все кубики имеют одинаковый размер, отношение "иа" между двумя
кубиками регулируется ограничением вида один-к-одному, обеспечиваю-
обеспечивающим целостность. Иными словами, если кубик А уже находится иа ку-
кубике В, то на кубике В не может быть никаких других кубиков. На столе
может поместиться более одного кубика.
Главной функцией процедуры "поместить" является сбор данных -
она собирает у пользователя сведения о необходимых изменениях базы
данных. Для защиты базы данных "на" от некорректных изменений в про-
процедуре "поместить" применяются ограничения, обеспечивающие целост-
целостность базы данных. К примеру,, если кубик А уже находится на кубике В,
а пользователь попытается поставить на В кубик С, то процедура "помес-
"поместить" откажется выполнить предписываемое перемещение и выдаст поль-
пользователю предупреждающее сообщение. Тем самым процедура "поместить"
следит за тем, чтобы в точке, где пользователь пытается вносить измене-
изменения в базу данных, отношение "на" между двумя кубиками имело вид
один-к-одному. Процедура "поместить" накладывает и другие ограниче-
ограничения, обеспечивающие целостность, такие как недопущение употребления
кубика, отсутствующего в текущем состоянии.
Первоначально база данных, описывающая мир кубиков, состоит из
следующих фактов:
наA, а, стол),
наA,6, стол).
наA,в, а).
наA, г, в).
теку щее_состояние A).
Факт "текущее_состояние" содержит наименование самого последнего
состояния базы данных.
294 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
Картина состояния
Экранно-ориентированная процедура "отобразить_сосюяние" строит
на экране дисплея изображение кубиков для заданного состояния базы
данных. Начальное состояние выглядит гак:
| ?— отобразить^ состояние A).
I г I
! ¦ !
! а ! ! б !
стол
Текст программы "отобразить_состояние" дан в приложении II.
Внесение изменений в базу данных
при помощи процедуры "поместить"
Процедура "поместить" вносит изменение в базу данных, генерируя
состояние-потомок текущего состояния. Она добавляет новые данные
в состояние-потомок, а затем деструктивно изменяет значение факта "те-
"текущее- состояние", превращая его в обозначение потомка. Первым аргу-
аргументом процедуры "поместить" является обозначение кубика, который
нужно передвинуть, а вторым аргументом служит место, куда нужно
поставить этот кубик.
Например, если текущее состояние — это ", то запрос
| ?— поместить (г, стол). % запрос A) ,"
вызовет добавление в программу следующих фраз:
текущее_со стояние B).
наB,г,стол).
опровергнутьB, на (_, г, в)).
Кроме того, из программы будет удалена фраза « текущее_состояниеA))> .
Выяснение того, где находятся кубики
Нижеследующий запрос покажет, где находятся кубики в состоянии
" базы данных:
! ?-послатьB, на(„,Х,У)).
6.7. ОПИСАНИЕ ИЗМЕНЕНИЙ БАЗЫ ДАННЫХ 295
Х = г
Y = стол ; % по состоянию "
Х = а
Y= стол ; % по состоянию "
Х=б
Y = стол ; % по состоянию "
Х = в
Y=a ; % по состоянию "
нет
Эта информация будет лучше восприниматься, если ее представить в
графическом виде:
\ ?— отобразить_состояние B).
1 а ' ' fi '
стол
Посмотрим, как будет выглядеть база данных после внесения еще не-
нескольких изменений.
', ?— поместить (а, б). % запрос B)
да
1 ?- поместить (в, г). % запрос C)
да
\ ?— текущее^состояние (X).
Х = 4
\ ?— отобразить_состояние D).
i i ||
¦ в i I a i
г I
СТОЛ
R
296 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ?
Реализация процедуры "поместить"
% запретить использование неизвестного кубика:
поместить (Кубик, Куда_поставить) :-
'-Я* проверить, отсутствуют ли
% Кубик и Куда_ноставить:
( not (на(.., Кубик, „))
Куда, носгавить \ ~ - стол,
п<Н(на(_., Куда .поставить, _))
), ¦•
write (' неверное обращение к кубику '), nl, !.
¦'^ запретить изменение, если переменная Куда_поставмть обозначав.
Ь кубик, на котором уже стоит другой кубик,
поместить (Кубик, Куда„по ставить) •--
Куда „постави1ь\ = = стол, " . .
текущее .состояние (Состояние),
посламь (Состояние, иа (Занят, Куда_поставить)),
writ« (Занят),
write(' уже находится на '),
\угНе(Куда-Поставить),п1,!.
% здесь база данных изменяется:
поместить (Кубик, Куда^поставить) :—
текущее—состояние (Состояние), % A)
НовоеСостояние is Состояние + 1, % B)
assert (порождение(НовоеСостояние,Состояние)), % C)
%
послать (Состояние, на (Кубик. Под кубиком)) , % D)
assert (опровергнуть (НовоеСостояние,
на(__, Кубик, Под_кубиком))), % E)
assert (на(НовоеСостояние, Кубик,
Куда_поставить)), % F)
retract(текущее_состояние(Состояние)), % G)
assert (текущее—состояние (НовоеСостояние)), !. % (8)
Ограничения, обеспечивающие целостность,
которые накладываются во время сбора данных
Первое правило "поместить" отвергает кубики, которые отсутствуют
в мире. Второе правило не разрешает пользователю ставить кубик на дру-
другой кубик, место над которым уже занято. Если два первых правила потер-
потерпят неудачу, то это будет означать, что ограничения, обеспечивающие
целостность базы данных, не будут нарушены при предлагаемом ее изме-
изменении. Собственно изменение осуществляется третьим правилом "помес-
h.7. ОПИСАНИЕ ИЗМЕНЕНИЙ БАЗЫ ДАННЫХ 297
¦•"¦л-". Подцели B) и C) этого правила устанавливают новое состояние
бя?м данных "порождение" Подцель D) выясняет текущее местоположе-
местоположение кубика "Кубик", а подцель E) опровергает это местоположение. Под-
цель F) добавляет к новому состоянию новое местоположение кубика
"Кубик". В заключение подцели G) и (8) деструктивно изменяют значе-
значение факта "текущее._состояние".
Перемещение колонки кубиков
В рассматриваемой версии программы "поместить" разрешается пе-
передвигать за один раз целую колонку кубиков. Иными словами, не запре-
запрещается перемещать кубик, если на нем стоит ещо один кубик. Это именно
то. что будет сделано в ответ на приведенный выше запрос B): « помес-
т ^(а. б)». Все кубики, стоящие над перемечаемым, наследуют новое
изложение этого кубика. Можно было бы добавить еще одно правило,
которое реализовывало бы ограничение, обеспечивающее целостность,
гарантируя то, что за один раз будет перемещаться только один кубик.
Оценка механизма наследования
Механизм наследования - это практическое воплощение концепции
наследования. Он пригоден для представления таких ситуаций, в которых
имеется множество состояний знаний, иерархически взаимосвязанных
друг с другом. Тем самым механизм наследования создает основу для
перевода на Пролог знаний, выраженных при помощи формализма фрей-
фреймов или объектно-ориентированного формализма. Уже существующую
фразу Пролог-программы легко можно адаптировать к этому механизму,
просто добавив в заголовок этой фразы дополнительный аргумент, содер-
Рис. б.ч
жащий имя состояния знаний. Примеры данного раздела показывают, что
применение механизма наследования позволяет реализовать удобную для
восприятия аксиоматизацию системы, свободную от побочных эффектов
Управления.
Неюстатком механизма наследования является ю, что он работает
неэффективно, если запросу к процедуре "послать" приходится анализи-
анализировать длинные цепи состояний. В приведенной форме, механизм насле-
298 ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИ%|
дования позволяет порожденному состоянию иметь более одного роди-
родителя. В обьектно-ориентированном формализме это называется множе*
ственным наследованием. К примеру, на рис. 6.9 показана ситуация, при
которой состояние Z наследует фразы и от состояния Y, и от состояния X,
Неэффективность процедуры "послать" возрастает, если состояние,
к которому обращен запрос, имеет более одного родителя. j
Процедура "послать" как предикат метаязыка
В разд. 0.9 отмечалось, что на уровне объектного языка смыслом от-
ответа на Пролог-запрос является либо соблюдение, либо несоблюдение
отношения, описанного в запросе. Но на уровне метаязыка смысл ответа
на запрос заключается в следующем:
Запрос доказуем или недоказуем
при помощи стратегии решения задач интерпретатора
в соответствии с фразами текущей программы.
Можно сказать, что смысл ответа на запрос определяется метаязыковым
предикатом с двумя следующими неявными параметрами: 1) должна
использоваться стратегия решения задач интерпретатора Пролога и 2) мно-
множество просматриваемых фраз ограничено фразами текущей программы.
Употребление механизма наследования приводит к небольшому изме-
изменению метаязыкового смысла ответа на запрос. При выполнении запроса
процедурой '"послать" смысл ответа состоит в следующем:
Запрос доказуем или недоказуем
при помощи стратегии решения задач интерпретатора
в соответствии с фразами программы,
относящимися к конкретному состоянию знаний.
Имя состояния знаний, являющееся первым аргументом процедуры "по-
"послать", служит обозначением множества фраз, относящихся к этому состоя-
состоянию. Поэтому механизм наследования в явной форме задает множество
фраз, которое будет использовано при обработке запроса. Следует рас-
рассматривать реализацию процедуры "послать" (как и реализацию проце-
процедуры "findall") как расширение обрабатывающей структуры интерпрета-
интерпретатора Пролога.
БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ
На подход к представлению знаний, принятый в данной главе, оказали
сильное влияние работы Хейеса [39], [40] и [41]. Хейес подчеркивает
важность теории модели для представления знаний.
Работы [9] и [10] являются хорошим введением в семантические
сети. Виноград [112] обсуждает ограничения семантических сетей, ука-
УПРАЖНЕНИЯ 299
зывая в то же время на преимущества фреймов. В работах [55], [56],
[39], [40] и [79] выдвигается точка зрения о том, что и семантические
сети, и фреймы можно рассматривать как различные виды синтаксической
формы логики предикатов.
Книга [35] является серьезным введением в язык объектно-ориенти-
объектно-ориентированного программирования Смолток-80. Первым языком объектно-
ориентированного программирования была СИМУЛА. Захватывающая
история разработки этого языка нашла отражение в работе [80]. Хьюитт *)
A977 г.) обсуждает управляющие структуры системы программирования,
базирующейся на понятии объекта (действующей силы). Понятие абстракт-
абстрактного типа данных разъясняется в книге [2].
Была проведена большая работа по исследованию того, как на языке
логического программирования можно выразить иные концепции пред-
представления знаний. В работах [55] и [56] под этим углом зрения рассмат-
рассматриваются семантические сети, в работах [40] и [77] — фреймы, а в работах
[98], [106] и [114] - объектно-ориентированное программирование. Ко-
вальски в работе [58] обсуждает многие другие концепции представления
знаний.
Хейес [40] рассматривает вопрос о том, как трактуется в логике
концепция наследования формализма фреймов. Механизм наследования,
описанный в данной главе, основывается на его идеях.
Аксиома фреймов рассматривается в работе [55, с. 133—138]. Вопросы
обретения знаний освещаются с позиций логического программирования
р работах [55] и [52].
УПРАЖНЬНИЯ
1. Отношение "является" в версии примера с птицами для языка Про-
Пролог (см. разд. 6.2) должно быть транзитивным для того, чтобы отражать
врсь смысл семантической сети. Иными словами, нижеследующий запрос
должен вырабатывать два ответа:
\ ?— является (твити, X).
X = канарейка ;
X - птица ;
нет
Пе[)сопределите предикат "является" таким образом, чтобы он стал тран-
транзитивным. (Предупреждение: превращение предиката "является" в тран-
*) Работа Хьюитта отсутствует в списке литературы. - Примеч. пер.
300
( параллелограмм Л
ГЛ. 6. ПРЕДСТАВЛЕНИЕ ЗНАНИЙ
площадь равна произведению основания на высоту
является
( прямоугольник \
все углы равны 90 градусов
является
Г квадрат \
все стороны равны
Рис. 6.10
зитивный может привести к нежелательным побочным воздействиям,
влияющим на другие правила программы, обращающиеся к предикату
"является" как к подцели, скажем, на правила "летает" и "цвет".)
2. Напишите программу, предназначенную для представления семанти-
семантической сети, изображенной на рис. 6.10.
3. Данное упражнение связано с программой, реализующей ведомость
сортов бумаги (см. разд. 6.6). Напишите запрос к самому верхнему состоя-
состоянию (((бумага))), позволяющий просмотреть все позиции ведомости,
содержащей сведения о бумаге.
Воспользуйтесь программой "з" для создания нового состояния с
именем «рулоны», находящегося под состоянием «бумага» и содержа-
содержащего только те позиции ведомости, в которых описывается рулонная
бумага.
Воспользуйтесь программами "отобразить" и "характер" для анализа
содержимого состояния "рулоны".
Примените программу "з" для создания нового состояния «гладкая»,
находящегося под состоянием «рулоны». Состояние «гладкая» должно
содержать только те позиции ведомости, которые несут информацию
о рулонной бумаге с гладкой поверхностью. Просмотрите при помощи
программы "отобразить" содержимое состояния «гладкая».
Исследуйте работу программы "послать" при помощи отладочных
средств Вашего интерпретатора.
Используя процедуру "findall" (см. приложение И), напишите про-
программу "счет", которая подсчитывает количество позиций ведомости,
описывающих бумагу для заданного состояния. Модифицируйте програм-
УПРАЖНЕНИЯ 301
му "з" таким образом, чтобы при образовании нового состояния поль-
пользователю автоматически сообщалось о количестве позиций ведомости,
связанных с этим состоянием.
4. Подумайте о других областях применения, которые можно аде-
адекватно представить в виде иерархии состояний, где информация из общего
состояния наследуется конкретным состоянием. Выберите одну из этих
предметных областей и воспользуйтесь механизмом наследования для
реализации ее представления.
ГЛАВА 7 .
ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ Н
7.1. СИСТЕМЫ ЭКСПЕРТНЫХ КОНСУЛЬТАЦИЙ
Два определения понятия "экспертная система"
В самом узком смысле термин экспертная система используется для
описания одной из небольшого чиста программ, разработанных обще-
общепризнанными специалистами в области инженерии знаний. Назначение
этих программ состоит в воспроизведении возможностей решения задач,
которыми обладает эксперт. Инженер по знаниям — это специалист, обу-
обученный искусству перенимать знания у экспертов и переводить эти знания
в форму, воспринимаемую компьютером. Большинство экспертных систем
не может полностью заменить человека. Такие системы используются для
повышения эффективности работы и расширения знаний персонала средней
квалификации.
В соответствии с альтернативным бихевиористическим определением
экспертная система - это любая программа, применяемая дчя экспертных
консультаций. Данное определение является более слабым, чем первое,
так как оно охватывает все программы, используемые в качестве эксперт-
экспертных систем, не учитывая того момента, что истинные эксперты могли
и не участвовать в создании )гих программ.
Некоторые разработчики экспертных систем сомневаются в том,
что потребность в инженерах по знаниям будет длительной. Они считают,
что компьютерные средства станут в достаточной степени "дружественны-
"дружественными" (т.е. пользователю будет легко и удобно работать с ними), так что
эксперты смогут напрямую пользоваться этими средствами. Во многих
отношениях это было Ьы очень желательно, так как позволило бы устра-
устранить возможные неточности или искажения, которые могут возникнуть
при интерпретации знаний эксперта инженером по знаниям. Однако для
такой непосредственной работы с ЭВМ эксперты, как минимум, должны
иметь желание изучить порядок пользования инструментальными ком-
компьютерными средствами и языками представления знаний.
Программы, ведущие себя как экспертные системы, но не основы-
основывающиеся на знаниях экспертов, называют также системами, базирующи-
базирующимися на знаниях, или системами экспертных консультаций. С точки зрения
методологии создания программ почти безразлично, проводились ли кон-
7.1. СИСТЕМЫ ЭКСПЕРТНЫХ КОНСУЛЬТАЦИЙ 303
сультации с экспертами перед написанием программы или нет. В данной
книге главное ннимание уделяется методологии создания программ. В
этой главе мы пользуемся термином системы экспертных консультаций,
под которым подразумеваем вес упомянутые выше разновидности экс-
экспертных систем.
Составные части системы экспертных консультаций
В любой системе экспертных консультаций обязательно должны иметь-
иметься следующие три компоненты:
1) язык представления знаний, с помощью которого можно интуитивно
представить знания о сложной области;
2) стратегия решения задач, позволяющая выполнять действия с пред-
представленными знаниями столь жя компетентно и умело, как это делают
эксперты-люди;
3) интерфейс с пользователем, обеспечивающий естественность и
удобство доступа к знаниям, которыми обладает программа, и способный
объяснить свои ответы как неопытным пользователям, так и пользовате-
пользователям-экспертам.
Пролог пригоден для разработки систем экспертных консультаций,
поскольку в нем имеются и язык представления знаний (фразы Хорна),
и общецелевая стрятегия решения задач, основанная на принципе резо-
резолюции. Концепции, заложенные в иные формализмы представления знаний,
другие стратегии решения задач, различные виды интерфейсов с пользо-
пользователем — все это можно реализовать на Прологе. Концепции представления
знаний были рассмотрены в гл. 6. Остальная часть дайной главы посвя-
посвящен;) "интеллектуальным" интерфейсам с пользователем и стратегиям
решения задач.
Интерфейс с пользователем
В предыдущих главах были продемонстрированы различные подходы
к созданию интерфейсов с пользователем: специальный язык запросов
к базе данных (см. разд. 5.5); нро1рамма, которая самостоятельно по-
пополняет свои знания, запрашивая у пользователя неизвестные ей сведения
(см. разд. 3.6 и 4.3); таблично-управляемый интерфейс с базой данных
(см. разд. 6.7); графическое представление информации, содержащейся
в базе данных (см. разд. 6.8). Один из подходов к созданию экранно-
ориентированного интерфейса, управляемого при помощи таблицы, рас-
рассматривается в приложении II.
Важной особенностью интерфейсов с пользователем многих систем
|сспертных консультаций является их способность объяснить, как были
йдены ответы. Это свойство необходимо для того, чтобы пользователи
эграммы прониклись к ней доверием. Если такое объяснение не будет
спечиваться, то у пользователей не будет оснований считать ответы
304 ¦„.¦•• * - ' " ГЛ- '—ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
экспертной системы достоверными. Ответ можно пояснить путем отобра-
отображения цепочки выводов, выполненных программой при поиске ответа.
В двух программах, представленных далее в этой главе, запоминается
цепочка выводов, выполняемых при обработке запроса. Эту цепочку
можно вывести на дисплей по требованию пользователя. На примере первой
программы, "вып" (сокращение от слова "выполнить"), демонстрируется
простейший способ запоминания цепочки выводов запроса. Следующая
программа, "вид" (сокращение от словосочетания "видимый Пролог"),
является расширением программы "вып", при котором обеспечивается
печать сообщений, поясняющих процесг выполнения запроса. Обе назван-
названные программы могут оказаться полезными при отладке других программ,
так как они дают программисту возможность непосредственно увидеть,
как в точности программа вырабатывает выдаваемые ею речуньгаты. Вы
сможете прийти к заючочерига, .что программа "вид" является более полез-
полезным отладочным инструментом, чем стандартные отладочные средства
некоторых версий Пролога.
Стратегия решения задач
В интерпретаторе Пролога применяется стратегия решения задач с
обратным ходом решения: он начинает свою работу с цели и продвигается
назад до тех пор, пока не встретит факты. (Понятие обратного хода ре-
решения было введено в разд. 0.6 и рассмотрено в гл. 3 и 5.) В некоторых
других системах решения задач (например, в системе, реализующей язык
0PS-5) принята стратегия с прямым ходом решения. В разд. 5.2 было
показано, как на Прологе можно реализовать стратегию с прямым ходом
решения (см. процедуру восходящего грамматического разбора "восх_
объект"). Некоторые задачи могут быть решены более изящно при по-
помощи стратегии с прямым ходом решения (к примеру, решение уравнений
или грамматический разбор языков, содержащих леворекурсивные кон-
конструкции, скажем, японского языка).
Альтернативная стратегия решения задач
Подробное объяснение стратегии решения задач, принятой в интер-
интерпретаторе языка Пролог, было дано в разд. 3.1. Процедура "вып", рас-
рассматриваемая в следующем разделе, в точности моделирует эту стратегию
решения задач. Поэтому можно трактовать процедуру "вып" как реали-
реализацию Пролога, написанную на самом Прологе. Точно такой же метод,
какой употребляется для реализации процедуры "вып", можно применить
и для реализации процедуры, в которой используется альтернативная
стратегия решения задач для выполнения Пролог-запроса. Такая програм-
программа, названная "иоц" (сокращение от словосочетания "интерпретатор,
который обнаруживает циклы"), представлена в предпоследнем разделе
дачной главы. Процедура "ион" может успешно обрабатывать ряд таких
7.2. ЗАПОМИНАНИЕ ПУТИ ВЫВОДА 305
запросов, при выполнении которых обычный интерпретатор Пролога по-
потерпит неудачу или войдет в бесконечный цикл. К примеру, процедура
"иоц" будет нормально работать с леворекурсивными процедурами.
7.2. ЗАПОМИНАНИЕ ПУТИ ВЫВОДА
Процедура "вып"
I Единственным аргументом процедуры "пып" (сокращение от слова
[''выполнить") является запрос, который эта процедура выполняет. Если
выполнение запроса окажется успешным, то процедура "вып" напечатает
запрос с конкретизированными неременными, а затем спросит пользовате-
пользователя, не желает ли он посмотреть путь доказательства или получить иной
огвег. 1:.сли ответов на запрос больше не существует, то процедура "вып"
потерпит неудачу.
Использование процедуры "вып "
Посмотрите, как процедура "вып" отвечает на запрос к нижеследующей
базе данных "owns", содержащей сведения о корпорациях, которые вла-
владеют другими корпорациями:
owns (ибм, ролм).
:• owns (ролм, дейтапойнт).
: owns (атт, телетайп).
{ ] ? - вып (owns (ибм, X)).
awns (ибм, ролм)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа.
Вскольку данный запрос может быть успешно выполнен, процедура
выи" печатает его, причем переменная X унифицирована с константой
« ролм ». Теперь, если пользователь введет символ "h", процедура "вып"
пояснит, как она выполнила запрос:
h
owns (ибм, ролм) содержится в программе.
Объяснение
Объяснение вырабатывается следующим образом. Если запрос унифи-
унифицируется с фактом, содержащимся в текущей программе, то на печать
выдаются текст запроса и слова ((содержится в программе)). Если запрос
унифицируется с правилом, входящим в текущую программу, то печа-
печатаются запрос и вопросительный знак. Далее по этой же схеме печатаются
подцели данного правила. Подцели выделяются при печати с помощью
отступа.
306 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
Ниже приводится пример сеанса работы с процедурой "вып", который
иллюстрирует выдачу объяснений этой процедурой. Обратите внимание
на то, что форма объяснений отражает форму фраз,которые используются
при выполнении запроса. Транзитивное отношение "holds" ("владеть
непосредственно или через посредника") основывается на приведенной
выше базе данных "owns" ("владеть непосредственно"). Отношение "holds"
ммрлжает то обстоятельство, что одна компания может владеть другой
косвенно, т.е. через промежуточную компанию.
holds (X, Y) : -
owns (X, Y).
holds (X, Y) : -
owns (X, Z),
holds (Z, Y).
| ?- вып (holds (ибм, X)). __ -
holds {ибм, ролм) % первый ответ .
введите символ h для просмотра пути доказательства или символ ;
для получения другого ответа.
h
holds (ибм, ролм) ?
owns (ибм, ролм) содержится в программе.
holds (ибм, ролм)
введите символ h для просмотра пути доказательства или символ ;
дп.ч получения другого ответа.
>
holds (ибм, дейтапойнт) % второй ответ
введите символ h для просмотра пути доказательства или символ ;
для получения другого ответа.
h
holds (ибм, дейтапойнт) ?
owns (ибм, ролм) содержится в программе,
holds (ролм, дейтапойнт) ?
owns (ролм, дейтапойнт) содержится в программе.
holds (ибм, дейтапойнт)
введите символ h для просмотра пути доказательства или символ ;
для получения другого ответа.
нет
Заметьте, что процедура "вып" повторно печатает запрос после ввода
пользователем символа h.
7.2. ЗАПОМИНАНИЕ ПУТИ ВЫВОДА 307
Как работает процедура "вып"
Единственным аргументом процедуры "вып" является запрос, который
она далее передает процедуре "выпО". Процедура "выпО" возвращает
структуру вида:
п (Запрос, ПутьДоказательства)
через свой второй аргумент. Здесь «Запрос» — это исходный запрос, а
«ПутьДоказательства» — это структура, описывающая шаги, необходимые
для доказательства запроса. В простейшем с /чае, когда запрос можно
доказать по единственному факту, переменная «ПутьДоказательства»
унифицируется со словами «есть_в_программе». Если запрос доказы-
доказывается при помощи правила, то переменная «ПутьДоказательства» уни-
унифицируется с рекурсивной структурой "п", содержащей все подцели пра-
правила.
После конкретизации переменная «ПутьДоказательства» передается
процедуре "спросить-у—пользователя". Эта процедура спрашивает поль-
пользователя, желает ли он просмотреть путь доказательства. В случае утвер-
утвердительного ответа вызывается процедура "отобразить_путь", а в против-
противном случае процедура "спросить— у—пользователя" терпит неудачу и про-
процедура "выпО" возвращается назад для поиска другого ответа.
Реализация программы "вып"
% выполнить запрос.
вып(Х):-
выпО (Х.Р),
спросйть_у—пользователя (X, Р).
спросить-у—пользователя (X, Р): —
write (X),nl,
write (' введите символ h для просмотра пути доказательства ),
write (' или символ ; '),nl,
write (' для получения другого ответа.'),
nl,
getO (A),getO (-), % ввод символа + перевод строки
А = 104, % ascii-код символа V
отобразить- путь ('', Р), %" означает отсутствие отступа
i;
спросить_у„пользователя (X, Р).
% исходный случай: последняя фраза была фактом.
% +
% Запрос Путь
выпО(Чгие, есть_в—программе) :— !.
08 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
% составной запрос; вернуть Р1, соединенную с Р2 запятой
выпО(А, Б), (Р1.Р2)):-
\г
вып0(А,Р1),
вын0(Б,Р2).
% простой запрос; вернуть структуру п( )
вып0(А,п(А,Р1)):-
clause (А, Тело),
выпО (Тело, Р1).
% отобразить путь выполнения:
% + +
отобразить _путь (Отступ, п (Фраза, есть_в_программе)):—
write (Отступ), write (Фраза),
write ('содержится в программе.'),nl, !.
% первая подцель составного запроса
отобразить_путь (Отступ, п (Фраза, (Подцель, Подцели) ) ):—
сцепить (Отступ,' ', НовыйОтступ),
отобразить—путь (НовыйОтступ, Подцель). +
i ¦¦'
отобразить_путь (НовыйОтступ, Подцели).
% остальные подцели составного запроса "'
отобразить—путь (Отступ, (Подцель, Путь)) :— S '
отобразить_путь (Отступ, Подцель),
1 'А'
отобразить-.путь (Отступ, Путь). '
отобразить_путь (Отступ, п(Фраза, Путь)) :—
write (Отступ), write (Фраза),
write ( ? ),nl, ( ¦ S;
сцепить (Отступ,' '.НовыйОтступ),
i;
отобразить_путь (НовыйОтступ, Путь).
% + + -
сцепить (X, Y, Z):— % сцепить два атома
name (X, Хсписок),
name (Y, Усписок),
присоединить (Хсписок, Усписок, Zсписок),
name (Z, ZcnncoK),!.
7.2. ЗАПОМИНАНИЕ ПУТИ ВЫВОДА 309
Доказательство факта
Лучше всего можно будет понять работу-.процедуры "вып", если рас-
рассмотреть входную и выходную информацию ее подцелей. Посмотрите,
что получится, если на вход процедуры "выпО" поступит запрос, который
является доказуемым по факту:
[ ?— выпО (owns (ибм, X), ПутьДоказательства).
Процедура "выпО" вызовет подцель "clause", которая унифицируем пере-
переменную X с константой «ролм», а переменную «Тело» -¦ с «true», так как
«owns (ибм, ролм)» - .по факт.
Следующий вызов прэцедуры "выпО" будет эквивалентен такому
запросу:
! ?- выпО (true.Pl).
Р1 = есть-в -программе
>твет на этот запрос получен по первому правилу "выпО". Значение пере-
перегенной Р1 передается далее и становится частью структуры "п", которая
озвращается через предыдущий вызов "выпО":
ПутьДоказательства = п (owns (ибм, ролм), есть_в^программе)
Доказательство правила
Предположим, что на вход процедуры "выпО" поступает запрос, ко-
который можно доказать только при помощи правила:
?- выпО (holds (ибм, X), Путь). %A)
эт вызов согласуется с третьим правилом процедуры "выпО". Подцель
ause" этого правила эквивалентна запросу:
I ?- clause (holds (ибм, Х),Тело1). %B)
Тело1 = owns (ибм, X).
Подцель "выпО" данного правила эквивалентна:
! ?- выпО (owns (ибм,Х),Р1). %C)
Р\ =n(owns (ибм, ролм), есть-в ^.программе)
А этот запрос — точно такой же, как и проанализированный ранее. Теперь
запрос A) к процедуре "выпО"даст следующий результат:
Путь = п (holds (ибм, ролм), п (owns (ибм, ролм),
есть-в программе)) *
310 ГЛ. 7 Ж? ПЕРТНЫЕ КОНСУЛЬТАЦИИ
Показ цепочки выводов
Требование просмотреть путь доказательств вызовет серию обращений
к процедуре "отобразить^.пугь'", то эквивалентно следующим запросам.
! ?— отобразить-лгуть (", и (holds (ибм. ролм).
n(owns (ибм, ролм),есть _в_ программе))).
holds (ибм, ролм) ?
1 ?— отобразить .путь (' ', п (owns (ибм,ролм), есть._в_программе)).
owns (ибм, ролм) содержится в программе.
Ограничения программы "выл" .
В приведенной версии программы "вып" не моделируется действие
предиката "сократить". Если на вход прспраммы "вып" подать запрос
к процедуре, содержащий предикат "сократить", то этот предикат будет
трактоваться как всегда истинная подцель. Предикат "сократить".не оста-
остановит процесс поиска с возвратом, выполняемый этой процедурой.
7.3. ВИДИМЫЙ ПРОЛОГ
Если ввести в программу "вып" несколько незначительных изменений,
то можно будет создать версию этой программы, которая будет пояснять
все решения интерпретатора, связанные с управлением, которые он при-
принимает при выполнении запроса. Объяснение будет согласовываться с
функционированием абстрактной машины, оризнтированной на paRorv
со стеком (см. гл. 3).
Получившаяся процедура, названная "вид" (сокращение от слово-
словосочетания "видимый Пролог"), выдает подробную распечатку, полезную
при отслеживании хода выполнения программ. Ко1да осуществляется
унификация запроса с фразой текущей программы, процедура "вид" пе-
печатает сообщение {(подц&1ъ=)), за которым следуют текст запроса и слова
((элементбд=У) (элемент базы данных), а затем располагается фраза про-
программы. Если унификация будет успешной, то программа "вид" напеча-
напечатает букву "У" (успех), в противном случае напечатана букча "Н" (не-
(неудача). Для начала сообщений о подцелях правила делается отступ отно-
относительно начала сообщения о заголовке этого правила. Если процедура
"вид" больше не сможет обнаружить фразу с теми же именем предиката
и количеством аргументов, что и в запросе, го она напечатает сообщение:
({¦.Конец базы данных X)). Приведем пример запроса.
| ?- BHfl(holds(H6M,X)).
% Заголовок первого правила "holds"
подцель-holds (ибм, _0) элемептбд-holds („38, _42) У
nodyeab=owns(u6M, -0) элементбд=омм(ибм. ролм) У \
7.3. ВИДИМЫЙ ПРОЛОГ 311
holds (ибм, ролм)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа
подцель=ом/т(ибм, -0) элементбд=о-ют{ролм, дептапопнт) Н
подцель=owns (ибм, _0) элементбд^о-wnsijiTT, телетайп) Н
: Конец базы данных owns.
% Заголовок второго правила "holds"
подцель=коШ$(ибм, _0) MeMem6d=holds (_38, _42) У
¦ nodyenb=owns(u6M, —78) элeмeнтбд=owlls(uбм. ролм) У
\ под цель=по1A$ (ролм, „0) элементбд-holds ( 339, _343) У
. nodyeAb^owns(ролм, ~0) элементбд=о\\т$(ибм, ролм) Н
\ nodyevib=owns (ролм, _0) элементбд= owns (ролм, дейтапойнт) У
I holds (ибм, дейтапойнт)
\ введите символ h для просмотра пути доказательства iliu символ ; для
i получения другого ответа
1подцель=оып5(ролм, _0) MP.MeHT6d=owns(aTT, телетайп) Н
1 : Конец базы данных owns.
подцель~holds (ролм, _0) элементбд=1гоШ$ (^339, -343) У
подit&ih=owns (ролм, .^379) 3AeMeHT6d=owns (ибм, ролм) Н
noditejib=owns(ролм, -379) элeмeнтбд=owпs(poлм, дейтапойнт)У
nodifefib=holds(дейтапойнт, _0) элементбд=ИоШ5(^702, ..706) У
nodue/ib=owns(дейтапойнт, _0) элeмeнтбд=owпs (ибм, ролм) Н
nodi(eAb=owns (дейтапойнт, _0) 3AeMCHr6d=owns (ролм,
дейтапойнт) Н
пoдцeль=owпs(дейтапойнт, -0KAeMeHT6d=owns(aTT, телетайп) Н
: Конец базы данных owns.
nodifeuib^holds(дейтапойнт, -0) элементбд^ИоМя (-702,-706) У
подцель^ owns (дейтапойнт, -742) 3AeMeHT6d=owns (ибм, ролм) Н
подцель =owns(дейтапойнт, -742) злeмeнтбд=owпs(poлм,
дейтапойнт) Н
подцель=(тп5 (дейтапойнт, -742) 3AeMeHT6d=owns(arT,
телетайп) Н
: Конец базы данных owns.
: Конец базы данных holds.
пoдцeль~owпs(poлм, -379} 3neMeHT6d=owns(aTT, телетайп) Н
: Конец базы данных owns.
: Конец базы данных holds.
пoдцeль=owпs(ибм, -78) злементбд=омп$ (ролм, дейтапойнт) Н
312 ГЛ.7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
iiodif&ib-owns (ибм, _ 75) элементбд-owns (атт, телетайп) Н
: Конец базы данных owns.
: Конец базы данных holds,
нет
Посмотрите, как много времени тратится впустую на поиск несуществую-
несуществующего третьего ответа.
Переход от программы "вып" к программе "вид"
Реализация программы "вид" очень похожа на реализацию программы
"вып". Первым аргументом процедуры "видО" (эквивалент процедуры
"выпО") в отличие от "выпО" является количество пробелов, на которое
следует сделать отступ. Однако главное различие между процедурами
"вид" и "вып" заключается в форме третьего правила процедуры "вилО"
Вместо простого вызова встроенного предиката "clause", при котором
первым аргументом служил бы запрос (как зто было сделано в процедуре
"выпО"), процедура "видО" создает копию запроса. Все аргументы.этого
нового запроса являются переменными. Новый запрос передается процеду-
процедуре "найти, фразу", которая возвращает тело фразы, унифицирующейся
с этим запросом. К примеру, если исходным является запрос «owiis(h6m,
—0)», то новым запросом будет «owns(_l, _2))). Процедура "найти—фра-
зу" может конкретизировать переменные нового запроса. После вызова
процедуры "найти_фразу" печатаются исходный запрос и запрос, выра-
выработанный данной процедурой, а затем предпринимается попытка унифи-
унификации этих двух фраз. Если унификация окажется успешной, то будет
напечатана буква "У" и процедура "выпО" будет вызвана рекурсивно вместе
с телом фразы, выработанным процедурой "найти_фразу". В противном
случае процедура "найти_фразу" возвратится назад для поиска другой
фразы в текущей программе.
Реализация программы "вид"
вид(Х):-
видО (",0,Путь),
спросить_.у„пользователя (Q, Путь).
спросить у-.пользователя (E,Путь):-
write (Q),nl.
write (' введите символ h для просмотра пути доказательства '),
write ('или символ ; для'),п],
write (' получения другого ответа '),
Ш,
ge'O (A), getO (_). % ввести символ + перевод строки
А -104, %asii - код символа 'R'
отобразить _путь (''. Путь),
7.3. ВИДИМЫЙ ПРОЛОГ 313
спросить—у_пользователя (Q, Путь),
% исходный случай для факта
'7с + Отступ + Запрос -Путь
видО(-, true, есть„в^программе):-¦• !.
% составной запрос
ви,цО (Отступ, @1, Q2), (Путь!,Лугь2))
I
' видО (О i ступ, Q1, ПупЛ),
[ аидО (Отступ, Q2, Путь2).
1% простой запрос
б;«лО (Отступ, Q1, и(Q1, Путь)) :-
% построить Q2:
% (Q2 - это копия Q1, но все его аргументы являются
\ % переменными)
| Q1 =.. [Предикат J Аргументы1], ..
| length (Аргументы 1, Длина),
построить-список (Длина, Аргументы2),
02 = . . [Предикат I Аргументы2],
найти^фразу (Отступ, Q2, Тело, Предикат),
write(OTciyn), write(' подцель= '), write(Ql),
write(' элементбд= '), wnte(Q2), write(' '),
( % успех, если Q1 унифицируется с Q2:
Ql =Q2, write (Y'),n\
7c неудача, если они не унифицируются:
not(Ql =Q2), write ('H'), nl. fail
сцепить (Отступ,' ', НовыйОтступ). У. отступ для подцелей
видО(НовыйОтступ, Тело, Путь).
% найти следующую фразу или напечатать сообщение о конце
% базы данных. .
найти—фразу (-, Q, Тело, ._) :-
clause (Предикат, Тело).
найти—фразу (Отступ, _, _, Предикат) : —
write (Отступ),
write (': Конец базы данных '), write (Предикат),
write ('. '),ni,
!, fail.
314 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
построить_список @, [ ]) :— !.
построить_список (N, [X I R]) :—
NN is N- 1,
построить-список (NN, R),!.
Процедуры "отобразить_путь" и "сцепить" будут такими же, как и в
приведенной ранее программе "вып".
7.4. ИНТЕРПРЕТАТОР, ОБНАРУЖИВАЮЩИЙ ЦИКЛЫ
Процедуры, которые зацикливаются
В нескольких местах данной книги мы уже выявляли Пролог-процеду-
Пролог-процедуры, которые, как казалось, должны были работать (так как они обладали
четкой декларативной семантикой), но вместо этого они вводили интер-
интерпретатор Пролога в бесконечный цикл.
Приведем, например, текст процедуры "нпредок" из разд. 1.5:
нпредок (А, Б) :— % A)
родитель (А, Б).
нпредок (А, Б):- % B)
нпредок (А, В),
родитель (В, Б).
Процедура "нпредок" сходна с процедурой "предок", которая работает
нормально. Отличие между двумя процедурами заключается лишь в том,
что порядок расположения подцелей в правиле B) процедуры "нпредок"
является леворекурсивным, а в процедуре "предок" - праворекурсивным.
Поскольку рекурсивный вызов процедуры "нпредок" выполняется рань-
раньше, чем подцель "родитель", переменная В не конкретизирована в точке
вызова процедуры "нпредок".
Когда интерпретатор Пролога попытается выполнить запрос к процеду-
процедуре "нпредок", то вначале он найдет все правильные ответы, а затем про-
продолжит рекурсию вплоть до исчерпания памяти.
Робастный решатель задач
Процедура "иоц" — это версия программы "вып", способная надежно
выполнять запросы к леворекурсивным программам, подобным процеду-
процедуре "нпредок". Метод, который применяется для придания программе
"иоц" свойств робастного решателя задач, аналогичен методу, использо-
использованному при составлении программы "тснр_путешествоватьЗ" из разд. 4.2-
Программа "иоц" регистрирует в списке заголовки всех фраз, которые она
встречает при обработке запроса. Если один и тот же заголовок фразы
встретится четыре раза подряд, то "иоц" потерпит неудачу. Это свойство
предохраняет программу "иоц" от попадания в бесконечные рекурсивные
циклы. Для того чтобы продемонстрировать возможности программы "иои
7.4. ИНТЕРПРЕТАТОР, ОБНАРУЖИВАЮЩИЙ ЦИКЛЫ 315
рассмотрим запрос к процедуре "нпредок". Предположим, что существует
нижеследующая база данных "родитель":
родитель (жб, лц).
родитель (жб, гг).
родитель (гг, вм).
Интерпретатор Пролога в бесконечной рекурсии после отыскания трех
(позитивных) ответов:
] ?— нпредок (жб, Z).
Z = лц ;
Z = гг ,
Z - вм ;
предупреждение: исчерпана стековая память.
Но процедура "иоц" сможет надежно выполнить такой запрос:
! ? -- иоц (нпредок (жб, X) ).
нпредок (жб, jiu)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа
I h
нпредок (жб, лц) ?
родитель (жб, лц) содержится в программе.
нпредок (жб, лц)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа
нпредок (жб, гг)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа
h
нпредок (жб, гг)?
родитель (жб, гг) содержится в программе.
нпредок (жб, гг)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа
нпредок (жб, вм)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа
h
нпредок (жб, вм) ?
316 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
нпредок {жб, гг) ?
родитель {жб, гг) содержится в программе,
родитель {гг, ем) содержится в программе.
нпредок {жб, ем)
введите символ h для просмотра пути доказательства или символ ; для
получения другого ответа
нет
Алгоритм работы программы "иоц"
Реализация программы "иоц" очень близка к реализации программы
'"выи". В процедуре "иоцО" (эквивалент процедуры "выпО") имеется но-
новый по сравнению с "выпО" первый аргумент — список подцелей, встре-
встретившихся к настоящему моменту При выполнении запроса. В третьем пра-
правиле процедуры "ионО" появилась новая по'дцель «not (унифицируемый
(Q1, След, 3))». Переменная «След» — это список подцелей, а переменная
«Ql)> — это текущая подцель. Процедура "унифицируемый" проверяет,
можно ли унифицировать Q1 с тремя элементами списка «След)) , распо-
расположенными подряд. Если можно, что процедура "иоцО" терпит неудачу
и возврашаегей назад для продолжения поиска. Число "три" здесь выбра-
выбрано произвольно. Если уменьшить это число до двух, то программа "иоц"
не сможет находить ответы в некоторых леворекурсивных задачах. Если
это число увеличить до четырех, то программа "иоц" сможет отыскивать
дополнительные ответы в определенных редко встречающихся ситуациях,
но это потребует значительно больших затрат машинного времени и опе-
оперативной памяти.
% интерпретатор, обнаруживающий циклы,
иоц (Q): -
иоцО([ ], О.Путь),
спросить_у_пользователя (Q, Путь).
спросить _у—пользователя (Q, Путь) : —
write (Q), nl,
write ('введиме символ h для просмотра пути доказательства'),
write ('или символ ; для') nl,
write ('получения другого ответа' ),
nl,
getO(A), getO(_), % ввод символа + перевод строки
А = 104, % 104 - это ascii - код' h' -
отобразить—путь ('', Путь),
спросить_у ^пользователя (Q, Путь),
7.4. ИНТЕРПРЕТАТОР, ОБНАРУЖИВАЮЩИЙ ЦИКЛЫ 317
% исходный случай для факта
% + + - '
% След Запрос Путь
иоцО(~, true, есть_в_программе) : —!.
% вторая фраза: составной запрос
иоцО(След, @1,02), (Р1.Р2)):-
иоцО(След, QLP1),
; иоцО(След, Q2.P2).
! % третья фраза: простой запрос
' иоцО(След,01,п@1,Р1)) :-
7с неудача, если три элемента подряд списка След
¦ % унифицируются с 01:
not (унифицируемый (Q1, След, 3)),
clause (Q1, Тело),
I иоцО([01 | След], Тело,Р).
% успех, если первый аргумент унифицируется с тремя подряд иду-
% шими элементами списка, заданного вторым аргументом.
унифицируемый (_, _, 0) : -! ¦
унифицируемый (А, [А ] R], N) :-
NN is N - 1,
!, унифицируемый (A, R, NN).
Программа "иоц" работает во многом аналогично программе "вып". От-
Отличие заключается в способе, которым список «След» (первый аргумент
процедуры "иоцО") набирает элементы по мере того, как глубина рекур-
рекурсивного вызова процедуры становится все большей. При выполнении
запроса
¦?_
иоц (нпредок (жб, X) ) •
будут выполняться нижеследующие вызовы процедуры "иоцО", демонстри-
демонстрирующие увеличение размера списка, являющегося первым аргументом:
,' ?- иоцО([ ], нпредок (жб,Х),Р1).
нпредок (жб, лц) % первый ответ, выдаваемый "иоц"
нпредок (жб, гг) % второй ответ, выдаваемый "иоц"
! ?- иоцО([нпредок(жб,Х)],ипредок(жб,С 1),Р2).
нпредок (жб, ем) % третий ответ, выдаваемый "иоц"
! ?- иоцО ([нпредок (жб, С1), нпредок (жб, X) ],
нпредок (жб, С2), РЗ).
318 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
! ?— иоцО ( [нпредок (жб, С2), нпредок (жб,С1),
нпредок (жб, X) ], нпредок (жб, СЗ), Р4).
J ?— not (унифицируемый (нпредок (жб, СЗ),
[нпредок (жб,С2);
нпредок (жб, С1),
нпредок (жб, X)],
3))-
нет
При выполнении запроса список «След» (первый аргумент процедуры
"иоцО") продолжает расти до тех пор, пока в нем не станет насчитывать-
насчитываться три элемента «нпредок (жб, _)», которые являются унифицируемыми
друг с другом. При попытке добавления четвертого такого же элемента
(«нпредок(жб, СЗ)») подцель «not (унифицируемый(Q1, След, 3)» потер-
потерпит неудачу и рекурсия в "иоц" будет прекращена. Заметьте, что точно в
этом месте (когда после отыскания трех ответов пользователь просит
найти еще один ответ) обычный интерпретатор Пролога вошел бы в бес-
бесконечный цикл.
Программа "иоц" как предикат метаязыка
Как отмечалось в разд. 0.9 и 6.5, смысл ответа на Пролог-запрос оп-
определяется метаязыковым предикатом с двумя неявными параметрами:
стратегией решения задач, которая является стратегией интерпретатора
языка Пролог, и множеством фраз, используемых при обработке запро-
запроса, которое ограничено фразами, содержащимися в текущей программе.
В разд. 6.5 рассматривалась роль процедуры "послать" как предиката
метаязыка, явно определяющего множество фраз, которое должно ис-
использоваться при выполнении запроса. С этих позиций процедура "иоц"
является метаязыковым предикатом, который явно задает стратегию
решения задач. Следовательно, смысл ответа на запрос, полученного при
помощи процедуры "иоц", заключается в следующем:
Запрос доказуем или недоказуем при помощи стратегии решения за-
задач, обнаруживающей циклы, в соответствии с фразами текущей прог-
программы.
7.5. ЗАКЛЮЧЕНИЕ: СТИЛЬ ПРОГРАММИРОВАНИЯ НА ПРОЛОГЕ
Суть компьютерной программы
Мы употребляем термин "система" для обозначения некоторой огра-
ограниченной части мира, которую программист хочет представить в виде
программы (т.е. предметную область, моделируемую программой). Задача
программиста, пишущего программу на любом языке, заключается в воп-
воплощении структуры нужной системы в программе. Прикладная програМ-
7.5. ЗАКЛЮЧЕНИЕ: СТИЛЬ ПРОЛОГА 319
ма состоит из двух компонент: из описания структуры системы и из про-
процедуры, способной преобразовать и реализовать смысл этого описания.
Программист, пользующийся процедурным языком, скажем языком Си,
как правило должен уделить внимание обеим компонентам. Как отме-
отмечалось в разд. 6.1, вычислительный формализм состоит из дескриптивного
языка и обрабатывающей структуры (т.е. множества процедур), способ-
способной реализовать смысл выражений дескриптивного языка. Следовательно,
программист, пользующийся вычислительным формализмом, может скон-
сконцентрировать свои силы на описании системы при помощи дескриптивного
языка этого формализма и положиться на обрабатывающую структуру
в том, что касается реализации смысла описания. Такой подход к исполь-
использованию вычислительного формализма адекватен только для таких ситуа-
ситуаций, когда формализм обладает достаточной выразительной силой для опи-
описания системы.
Три стадии изучения Пролога
Если трактовать Пролог как вычислительный формализм, то он состоит
из дескриптивного языка и обрабатывающей структуры (интерпретатора),
реализующей формальный смысл выражений этого дескриптивного языка.
Процесс обучения программированию на Прологе можно разделить на три
стадии. На первой стадии программист познает силу Пролога как вычисли-
вычислительного формализма, занимаясь написанием программ, состоящих из
чисто декларативных фраз. Иными словами, программист должен изучить
основные свойства обрабатывающей структуры Пролога (т.е. действия ин-
интерпретатора) , когда не применяются побочные эффекты (к их числу отно-
относятся встроенные предикаты "сократить", "assert", "retract", "write" и т.д.).
Именно поэтому в дайной главе и в гл. 3 так много внимания уделялось
обсуждению стратегии решения задач интерпретатора Пролога.
Со временем, однако, программист начинает сталкиваться с такими
ситуациями, при которых нельзя обойтись одной лишь основной обраба-
1швающей структурой Пролога. К примеру, могут потребоваться такие
вычисления, которые невозможно осуществить на Прологе без применения
^Юбочных эффектов. В этой ситуации программист не может рассчитывать
Ма то, что обрабатывающая структура интерпретатора окажется достаточной
для выполняемой программы. Поэтому на второй стадии обучения языку
Пролог программист узнает, как нужно пользоваться побочными эффек-
эффектами для построения сложных управляющих структур в Пролог-программе.
На этой стадии обучения требуется усвоить бихевиористический подход к
языку (см. разд. 4.3). Во время данной фазы обучения программисты мо-
могут почувствовать искушение пользоваться побочными эффектами чуть ли
не в каждой фразе программы.
Пролог-процедура, не полагающаяся на побочные эффекты, обладает
Четким декларативным смыслом и целиком является составной частью
320 ГЛ.7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
дескриптивной части программы. Однако Пролог-процедура с побочными
эффектами не имеет декларативного смысла. Если побочные эффекты
встречаются в процедуре, ориентированной на конкретную область приме-
применения (примером такой специализированной процедуры может служить
процедура "место" из разд. 3.7), то такую процедуру следует рассматри-
рассматривать как некоторую смесь описания и обработки. Такая процедура ухуд-
ухудшает свойства Пролога как вычислительного формализма, делая менее
четким различие между описанием и обработкой.
Если побочные эффекты употребляются в процедуре общего назна-
назначения (примерами таких универсальных процедур являются процедура
"findall" из приложения II и процедура "послать" из гл. 6), то такую про-
процедуру можно рассматривать как составную часть обрабатывающей струк-
структуры прикладной программы. Пролог, расширенный за счег таких про
цедур, будет более мощным вычислительным формализмом, чем Проло!
сам по себе, потому что при наличии данных процедур можно будет опи
сывать более сложные системы при помощи" чисто декларативных фраз
языка Пролог.
Следовательно, на третьей стадии изучения языка Пролог програм-
программист должен усвоить некоторую дисциплину при Программировании, за-
заключающуюся в том, что для сохранения чисто описательного характера
программного текста, ориентированного на конкретное применение, необ-
необходимо сводить все побочные эффекты в процедуры общего назначения.
Итак, в тех случаях, когда вычислительный формализм Пролога не пред-
представляется адекватным для описания некоторой Программной ситуации
(или для представления системы), всегда существует выбор между ухуд-
ухудшением свойств формализма за счет добавления побочных эффектов к
фразам, ориентированным на конкретное применение, и расширением
формализма посредством написания процедур общего назначения. В ниже-
нижеследующих двух правилах хорошего стиля программирования на Прологе
поощряется выбор второй альтернативы.
Два правила хорошего стиля программирования иа Прологе.
Декларативная граница
Первое правило таково:
Делайте так, чтобы дескриптивная часть программы четко отличались
от обрабатывающей структуры программы.
Иными словами, это правило гласит: не размещайте побочные эффекты
(которые являются процедурными элементами) во фразах, описывающих
конкретную область применения. Если следовать данному правилу, то в
значительной мере сохранятся ясность программы и легкость ее сопро-
сопровождения. ;
7.5. ЗАКЛЮЧЕНИЕ: СТИЛЬ ПРОЛОГА 321
Второе правило состоит в следующем:
Установите декларативную границу мелСду дескриптивной частью
программы и обрабатывающей структурой таким образом, чтобы
фразы, ориентированные на конкретное применение, были целиком
дескриптивными.
На той стороне границы, где располагается обрабатывающая структура,
процедура делает все необходимое для установления отношения. На той
стороне границы, где располагается дескриптивная часть, обращение к про-
процедуре, расширяющей обрабатывающую структуру, имеет вид отношения,
обладающего декларативным смыслом. Частично этот декларативный
смысл находится на уровне метаязыка, так как в процедуре есть побочные
эффекты, изменяющие стратегию решения задач интерпретатора. Благодаря
существованию границы можно в качестве подцели дескриптивной фразы
употребить вызов процедуры, что не приведет к "размыванию" декларатив-
декларативной семантики этой фразы.
При разработке любой конкретной прикладной программы возникает
трудная задача: необходимо решить, где провести декларативную границу
между описанием и обработкой. Вообще говоря, будет легче понимать и
сопровождать программу, написанную при помощи вычислительного
формализма, если форма этой программы будет изоморфна форме описы-
описываемой ею системы (т.е. для каждой вариации формы системы будет иметь-
иметься соответствующая вариация формы дескриптивной части программы и
наоборот). Поэтому если необходимо расширить Пролог как формализм,
важно сделать это таким образом, чтобы был обеспечен изоморфизм между
дескриптивными фразами и системой, которую они описывают. В идеале,
выше уровня декларативного интерфейса должен существовать изомор-
изоморфизм между формой программы и формой системы. Ниже уровня декла-
декларативного интерфейса допускается свободная реализация нужного поведе-
поведения программы.
Примеры декларативной границы
Рассмотрим несколько примеров декларативных границ. Пусть задача
состоит в том, чтобы написать фразу, которая определяет лицо М каклшъ-
одиночку лица Р (ребенка), если М — мать Р, М живет с Р, М разведена и
М не состоит в повторном браке. Предположим, что база данных "мать"
очень велика. Нужно добавить в правило такую управляющую информа-
информацию, чтобы интерпретатор не терял понапрасну время на поиск более чем
одного значения М при обработке запроса к правилу, в котором перемен-
переменная Р конкретизирована, а переменная М не конкретизирована.
11. Дж. Малпас
322 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
Первое решение задачи
% Одна Много
мать— одиночка1 (М, Р) : —
nonvar (P),
мать(М,Р),
!, % у Р только одна мать, поэтому запретить возврат назад.
живет—с(М,Р),
разведена (М),
not (повторно—замужем (М) ).
мать_одиночка1 (М,Р) : —
var (P),
мать(М,Р),
живет_х(М,Р),
разведена (М),
not (повторно-замужем (М) ).
мать (сюзан, бобби).
мать (кетлин, фред).
мать (исадора, Мишель).
мать (барбара, венди).
мать (барбара, стив).
живет—с (сюзан, бобби).
>'*. живет_с (исадора, Мишель).
¦lS живет_с(барбара,венди). ,:-.
w живет_с(барбара, стив). ж?>
разведена (кетлин). J*:'
разведена (исадора). '**'
разведена (барбара). •*
v повторно_замужем (кетлин).
Для проверки того, правильно ли процедура "мать—одиночка1" реша-
решает сформулированную выше задачу, воспользуйтесь отладочными средства-
средствами Вашего интерпретатора при выполнении запроса:
] ?—мать_одиночка (Кто, венди).
Кто = барбара ; •
нет
Выходная информация, выдаваемая отладочными средствами, покажет,
что интерпретатор не возвращается назад для поиска второй матери Венди-
В приведенном первом решении декларативная граница расположена
на уровне процедуры "мать_одиночка1". Реализация процедуры "мать—оди-
"мать—одиночка! " не обладает декларативным смыслом, так как в ней употребляют-
употребляются побочные эффекты. Однако вызов процедуры "мать_одиночка1" имеет
7.5. ЗАКЛЮЧЕНИЕ: СТИЛЬ ПРОЛОГА 323
декларативный смысл. Лучше всего рассматривать процедуру "мать_оди-
ночка1" как процедуру, которая выполняет все действия, необходимые
для установления отношения "мать^одиночка!" между своими аргумента-
аргументами, причем делает это эффективно.
Второе решение задачи
I мать_одиночка2(М,Р) : —
I ом_мать(М,Р),
I живет_с(М,Р),
| разведена (М),
not (повторно_замужем (М) ).
% промежуточная процедура доступа к базе данных "мать", реализую-
% щая ограничение вида один-к-многим:
% Одна Много
,у. m ¦«¦¦.•заявив **эд*ш«*: ¦¦
ом_мать(М, Р) :- • о
\ nonvar(P), ', "*у '• '' '"/)",
• мать(М,Р),!. '' "' % "л "
ом_мать(М, Р) :— ,,
var(P), •''«
мать(М.Р). ''"-"•'
; В этом решении декларативная граница проходит на уровне процедуры
"ом_мать". Процедура выполняет все необходимые действия для уста-
установления отношения "мать" между своими аргументами и делает это
эффективно. Поскольку вызов процедуры "ом_мать" обладает деклара-
i тивным смыслом, тело правила "мать—одиночка2" также обладает им,
а поэтому оно находится на дескриптивной стороне границы.
Второе решение является несколько более предпочтительным, чем
первое, так как декларативная граница располагается на более низком
уровне. К тому же процедуру "ом_мать" можно использовать и в
других фразах в качестве эффективной промежуточной процедуры, обес-
обеспечивающей доступ к базе данных "мать". Но у обоих решений есть об-
общий недостаток — они нарушают первое правило хорошего стиля. В пер-
первом решении во фразу процедуры "мать—одиночкаГ', ориентирован-
ориентированную на конкретное применение, вводятся побочные эффекты управления.
Во втором решении побочные эффекты управления добавляются в ориен-
ориентированную на конкретное применение фразу процедуры "ом_мать".
Третье решение задачи
Существует и третье решение, в котором полностью разделены обра-
'батывающая структура и описание. В этом решении требуется объявление
ftoro, что аргументы отношения "мать" регулируются ограничением, обес-
324 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
печивающим целостность, вида один-к-многим, а также нужен решатель
задач, способный воспользоваться этой информацией.
мать_одиночкаЗ (М, Р) : — -:г,
мать(М,Р), ,«>'
живет _х(М,Р),
разведена (М),
not (повторно-замужем (М) ).
% объявить свойство "один-к-многим" отношения "мать":
% Отношение Одна Много
один_много (мать (Мать, Ребенок), Мать, Ребенок).
% решатель задач, который знает о существовании отношений авда
% один-к-многим":
рз (true) : - !.
рз((А, Б) :- % составной запрос
\t ¦
РЗ(А),
рз(Б).
рз (А) : — % особый случай: А — это отношение вида
% "один-к-многим"
один_много (А, X, Y),
I
0M-pa(A,X,Y). .„
рз (А) : — % А не является отношением вида "один-к-мнопш"
clause (А,Тело), фч
рз(Тело). ' ь,
% эффективно обработать отношение вида "один-к-многим":
% Один Много
ом_рз(А,Х, Y) :-
nonvar(Y), "il'
clause (А,Тело),
рз(Тело),!. -• '-'
ом_рз(А>Х,У) :-
var(Y),
clause (А, Тело),
рз(Тело).
Обратите внимание на сходство процедур "рз" (сокращение от слово-
словосочетания "решатель задач") и "выпО" (см. разд. 7.2). В процедуре "рз"
есть дополнительная фраза, предназначенная для работы с запросами,
которые регулируются ограничением, обеспечивающим целостность, вида
7.5. ЗАКЛЮЧЕНИЕ: СТИЛЬ ПРОЛОГА 325
один-к-многим. Процедура "ом_рз" очень похожа по форме на процедуру
"ом_мать".
В третьем решении декларативная граница находится на уровне про-
процедуры "рз". Процедура "рз" выполняет все действия, необходимые для
установления нижеследующего свойства своего аргумента (запроса):
Запрос доказуем в соответствии с множеством фраз текущей програм-
программы при использовании стратегии, в которой учитывается информация
о том, какие отношения регулируются ограничением вида один-к-мно-
один-к-многим, обеспечивающим их целостность.
Декларативная управляющая информация
В результате дополнительных усилий, потребовавшихся на состав-
составление процедуры "рз", процедура "мать^одиночкаЗ" теперь целиком рас-
располагается на дескриптивной стороне границы, и поэтому больше нет необ-
необходимости в использовании промежуточной процедуры, обеспечивающей
доступ к базе данных "мать". Факт "один—много" также находится на
дескриптивной стороне границы, так как он декларирует свойство другой
части описания. Смысл этого факта находится на уровне метаязыка.
Данный факт содержит декларативную управляющую информацию, кото-
которая используется процедурой "рз".
Другие примеры
В книге приводились и другие примеры программистских задач, демон-
демонстрирующие то, как применение двух правил хорошего стиля программиро-
программирования приводит к четкому и легко читаемому решению, которое имеет
широкую сферу применения. Сравните решение одной и той же задачи при
помощи процедуры "место" (см. разд. 3.7), нарушающей первое правило,
и при помощи процедуры "найти_или-спросить", которая это правило не
нарушает. Сравните решение одной и той же задачи посредством про-
процедуры "итог_окл"из разд. 3.11 и посредством процедур "findall" и "сумми-
"суммировать". В заключение сравните пример "собрание" из разд. 6.3 с аналогич-
аналогичным примером из разд. 6.4, в котором применена процедура "послать".
В последнем примере все фразы, ориентированные на конкретное приме-
применение, являются структурно изоморфными по отношению к опись: саемой
ими системе, а подробности того, как это достигается, скрыты внутри про-
процедуры "послать".
Пролог как эффективный вычислительный формализм
Пролог не является идеальным вычислительным формализмом, так
как существует много программных ситуаций, с которыми интерпретатор
не может справиться без дополнительной управляющей информации. Но
если программист будет придерживаться двух упомянутых правил хоро-
хорошего стиля программирования, то он сможет превратить Пролог в эффек-
326 ГЛ. 7. ЭКСПЕРТНЫЕ КОНСУЛЬТАЦИИ
тивный вычислительный формализм для любой конкретной сферы приме-
применения. Установление в программе декларативной границы позволяет четко
судить о том, какие части программы являются дескриптивными, а какие —
обрабатывающими. Как показывает последний пример данной главы, даже
управляющую информацию можно включить в дескриптивную часть прог-
программы.
Дисциплина при программировании на языке Пролог сводится к тому,
что расширение возможностей интерпретатора, когда это необходимо, дос-
достигается при помощи написания процедур, причем это следует делать таким
образом, чтобы сохранялся "дух" Пролога как вычислительного форма-
формализма. Программист, придерживающийся этой дисциплины, имеет то преи-
преимущество, что он может мысленно представлять структуру прикладных
областей на высоком концептуальном уровне.
БИБЛИОГРАФИЧЕСКИЕ ЗАМЕТКИ Ж^
Общепринятое определение экспертной системы можно найти в книге
[42]. Бихевиористическое определение дано в работе [58].
Многие экспертные системы обладают способностью объяснять свои
ответы. Прототипом того, как выдается объяснение в процедуре "вып",
послужило аналогичное свойство языка APES [38].
Процедура "вып" является аналогом процедуры "eval" [23]. Различ-
Различные виды интерпретаторов, обнаруживающих циклы, рассматриваются в
докладе [11].
Обсуждение стиля программирования на Прологе, приведенное в кон-
конце главы, во многом сходно с материалом, изложенным в работе [58].
УПРАЖНЕНИЯ
1. Введите базу данных "путешествие/4", содержащую циклические
данные, а затем воспользуйтесь программой "иоц" для выполнения запроса
к процедуре "можно_путешествовать4". Что получится в результате этих
действий?
Попытайтесь применить программу "иоц" для работы с другими прог-
программами, при выполнении которых возникали проблемы. Работает ли ка-
какая-нибудь из этих программ под управлением интерпретатора, обнаружи-
обнаруживающего циклы, в тех ситуациях, когда она не работала при использовании
обычного интерпретатора? Почему работает или же не работает?
2. Вызов процедуры "findall" (см. разд. 3.9) объявляет отношение меж-
между запросом и всеми ответами на этот запрос; вызов процедуры "послать"
(см. разд. 6.4) объявляет, доказуем ли запрос в соответствии с фразами,
которые связаны с определенным состоянием. Какое отношение объявляет
вызов процедуры "поместить" (см. разд. 6.5)? Можно ли переписать проце-
V - .
УПРАЖНЕНИЯ ' " '' ' 327
дуру "поместить" так, чтобы, она стала обладать более четким декларатив-
декларативным смыслом?
3. Процедура "рз" (см. разд. 7.5) может оптимизировать выполнение
запросов к отношению, вид которого объявлен как "один_много". Попы-
Попытайтесь расширить процедуру "рз" так, чтобы она смогла оптимизировать
запросы к отношениям, вид которых объявлен как "один—один"и "мно-
го—один" (см. разд. 1.7). •¦ ,' , ¦ • : ¦• t:l;-•
¦''
];}
•.,.,..,=. .'.ft,.
¦V '
D ^ '
m
ч,..',,,л.Мл'М.я ;,VJ'rt
ШЧ
ПРИЛОЖЕНИЯ . ;
* ' , I. ОСНОВНАЯ ТЕРМИНОЛОГИЯ 'f1 ¦
Аксиома (axiom). В логике высказываний или в логике предикатов
первого порядка аксиома — это ППФ, которая полагается истинной. Мно-
Множество аксиом, описывающих структуру некоторой области знаний, назы-
называется теорией (см. разд. 0.4 и 0.5). Если Пролог-программа используется
для описания структуры системы, то каждую фразу программы можно
рассматривать как аксиому.
Аксиоматизация (axiomatization). В логике предикатов аксиоматиза-
аксиоматизация (или аксиоматическое определение) отношения — это множество ак-
аксиом, из которых при помощи правил вывода могут быть получены все
истинные конкретные реализации данного отношения.
"Аргументность" (arity). Количество аргументов структуры или пре-
предиката можно назвать его аргументностью.
Атом (atom). Атом — это нечисловая константа. Он обычно записывает-
записывается как одно слово без кавычек. Примеры атомов:
hello * '#$%' 'New York'
Апострофы (одиночные кавычки) употребляются при записи атомов,
состоящих из нескольких слов, или атомов, начинающихся с заглавной
буквы.
Встроенный предикат (built-in predicate). В каждой конкретной вер-
версии языка Пролог имеются определенные встроенные предикаты, перед
использованием которых не требуется явного их просмотра интерпрета-
интерпретатором Пролога. В разд. 3.3—3.10 рассматриваются наиболее часто встречаю-
встречающиеся в языке Пролог встроенные предикаты. Точный перечень встроен-
встроенных предикатов для Вашей версии языка можно найти в справочных ма-
материалах по этой версии.
Вывод (inference). Процесс получения заключения из некоторых
предположений называется выполнением вывода.
Детерминированный (determinate). Процедура является детермини-
детерминированной, если она будет успешно выполнена только один раз. Составной
запрос (или тело правила) будет детерминированным, если после его
I. ОСНОВНАЯ ТЕРМИНОЛОГИЯ 329
выполнения интерпретатор окажется не в состоянии осуществить поиск
с возвратом ни для какой подцели этого запроса.
Запрос (Цель) (query (goal)). С позиции декларативной семантики
Пролога запрос — это вопрос, который пользователь задает Пролог-систе-
Пролог-системе о том, соблюдается ли конкретная реализация отношения. С позиции
процедурной семантики Пролога запрос можно рассматривать как вызов
процедуры.
Простой запрос записывается как имя предиката, за которым следуют
аргументы внутри скобок и точка. Например, запрос
! ?-отец(эдвард, ральф). »•¦*'•
обращается к предикату "отец/2".
Если запрос не содержит переменных, то система ответит на него либо
да (yes), либо нет (по). Если же в запросе есть переменные, то система
предпримет попытку найти такие значения этих переменных, при которых
запрос будет истинным. После того как система найдет один из ответов,
пользователь, набрав символ "; ", может попросить систему провести
поиск дополнительных ответов.
Составной запрос состоит из двух или более простых запросов, связан-
связанных соединителями "и" (записывается как запятая) и "или" (записывается
как точка с запятой). Каждая компонента составного запроса называется
подцелью. Ниже приводится пример составного запроса, предназначенного
для отыскания имени деда Ральфа:
! ?-отец (Д, О), отец (О, ральф).
Поскольку обе подцели этого составного запроса связаны соедините-
соединителем "и", то для истинности всего составного запроса должны быть истин-
истинными одновременно обе его подцели. Переменная "О" — это разделяемая
переменная, которая ввиду необходимости унификации должна иметь
одно и то же значение в каждой из двух подцелей.
Конкретизация (instantiation). Переменная в языке Пролог конкрети-
конкретизируется, когда при выполнении запроса она получает в качестве значения
константу или структуру.
Константа (constant). Константа — это либо целое число A, 20, —10),
либо число с плавающей точкой C.1417), либо атом.
Операция (operator). Операция — это имя предиката или структуры,
которое может быть записано в инфиксной, префиксной или постфиксной
форме (см. разд. ЗЛО). Например, символ "+" — это имя структуры,
объявленное как инфиксная операция.
Переменная (variable). Переменная — это одна из разновидностей
термов Пролога, значением переменной может быть константа или струк-
структура. Переменная обозначается словом, начинающимся с заглавной буквы
330 ЧДОШЯи+1-Ш ПРИЛОЖЕНИЯ
X Имя • ¦• _е- •;--:¦ 305 ;<т- "•:•». -.•¦
Правило {rule). Правило — это фраза Хорна с одним или более условий,
например: ( '
попучить_по_шее(ральф) :— ,
хэкер(ральф). iW!
В данном правиле « хэкер(ральф) » — это одно и единственное условие,
а « получить_по_шее (ральф) >> — это заключение.
Правило вывода {inference rule). В исчислении высказываний и в ис-
исчислении предикатов правило вывода специфицирует синтаксическую
форму логически корректного вывода (см. разд. 0.4 и 0.5). Примером
правила вывода является логическое правило modus ponens:
Из р —> q и р выводится q
В табл. 0.2 приведены и другие правила. Резолюция — это правило вывода
для фразовой формы логики предикатов.
Предикат {predicate). Предикат — это отношение, существующее
между некоторым фиксированным набором аргументов. Предикат иден-
идентифицируется по своему имени и количеству аргументов ("аргуметнос-
ти") . Обращение к предикату записывается так: "J "! • .«>-¦•
имя(арг1, арг2,.. . , aprN) -;< , А, ¦, :
В языке Пролог предикаты определяются при помощи процедур.
Просматривать {consult). Во время сеанса работы интерпретатор Про-
Пролога просматривает файл с фразами, написанными на этом языке, после
чего данные фразы становятся частью текущей Пролог-программы. В боль-
большинстве версий Пролога для выполнения этого действия имеется встроен-
встроенный предикат "consult /1 "¦
Процедура {procedure). Процедура — это множество фраз, в котором
в заголовке каждой фразы присутствует одно и то же имя предиката и име-
имеется одинаковое количество аргументов. Например, нижеследующие две
фразы из гл. 1:
предок (А, Б) :- % A) /;.
родитель (А, Б). ; ¦•¦ , , ''.!,Щ>
предок(А, Б) :- ,,^.,. % B) ,/ ; ^,
родитель (В, Б), . .., ?$г , . . !jf,.,. ',.-,-¦.<¦."|йт
предок (А, В).
образуют процедуру "предок/2". Этой процедурой определяется предикат
"предок/2".
Подцель {subgoal). Подцель - это условие в теле правила или в состав-
составном запросе:'' "¦ * -; <уль^<ъ.--'- "-:;--> ••-"-¦¦¦'¦ '.аи...,.., , .„.&<....,¦
I. ОСНОВНАЯ ТЕРМИНОЛОГИЯ 331
Поток {stream). Данные, организованные последовательно, называют-
называются потоком. В программе можно интерпретировать как поток канал ввода-
вывода, используемый для связи с дисковыми файлами или с внешней
средой. Рекурсивную структуру данных, такую как список, также можно
считать потоком.
Словарь (lexicon). Словарь формального языка — зто множество сим-
символических обозначений, используемых для написания предложений этого
языка.
Сократить (cut). Встроенный предикат "сократить" (записывается
в виде символа "!") всегда явлется истинным. Его применение останав-
останавливает поиск с возвратом (см. разд. 3.2).
Список (list). Список — это особый тип структуры, записываемый
как множество из нуля или более элементов, заключенных в квадратные
скобки. Если список не содержит элементов, то говорят, что он пуст. Пус-
Пустой список записывается как [ ]. Ниже приведены примеры списков,
все элементы которых заданы явно:
[аа, bb,cc] [X, Y] [Имя] [[x,y],z]
В следующих примерах явно задаются только первые несколько элемен-
элементов каждого списка. Остальная часть списка представляется переменной,
стоящей справа от символа " | ":
rt(.fo<Jf
[X|Y] [a,b,c|Y] [[х, у] ] Остаток] Ц
Символ " ! " называется конструктором списка. Элементы, стоящие слева
от символа " ! ", называются началом списка. Переменная, расположенная
справа от символа " | ", называется остатком списка; она представляет
список любой длины.
Структура (structure) (называется также составным термом). Струк-
Структура — это сложный объект данных, идентифицируемый своим именем
и количеством аргументов. Структура записывается как имя, за которым
следует один или большее число аргументов, заключенных в скобки. При-
Пример структуры "отец/1": oq'
¦ifiv
отец (джордж). ,.,
Здесь "отец" - это имя структуры, а "джордж" - это первый и единствен-
единственный ее аргумент. Аргументом структуры может служить другая структура,
например:
отец (отец (джордж) ). t>
Атом можно рассматривать как структуру, не имеющую аргументов. '
1
332 К;П1>МОМ««* ПРИЛОЖЕНИЯ
Теория (theory). Теория в логике высказываний или в логике преди-
предикатов — это множество аксиом, описывающих область знаний (см. разд. 0.4
и 0.5). Если программа на Прологе используется для описания структуры
некоторой системы, то такую программу можно рассматривать как теорию.
Терм (term). Аргументом предиката или структуры должен быть
терм. Терм — это либо константа, либо переменная, либо структура.
Унификация (unification). Унификация — это процесс согласования
подцели с заголовком фразы при выполнении запроса. Подцель унифици-
унифицируется с заголовком фразы, если выполняются три следующие условия:
1) у них одинаковые имена; 2) они имеют одинаковое количество аргу-
аргументов; 3) все их аргументы можно унифицировать. Унификация аргу-
аргументов осуществляется в соответствии со следующими правилами:
1. Две константы унифицируются друг с другом, если они идентичны.
2. Переменная унифицируется с Константой или со структурой. В ре-
результате унификации переменная конкретизируется, получая значение
константы или структуры.
3. Переменная унифицируется с другой переменной. В результате
они становятся одной и той же переменной.
4. Структура унифицируется с другой структурой, если у них одинако-
одинаковые имена, они имеют одинаковое количество аргументов и все их аргу-
аргументы могут быть унифицированы.
Факт (или единичная фраза) (fact (or unit clause)). Факт — это фраза
Хорна, не имеющая условий, т.е. обладающая пустым телом (см. разд. 1.2).
Примеры фактов:
король(людовик, франция).
имеют_клюв (птицы).
служащий (нэнси, обработка _ данных, 55000).
Фраза (clause). См. фраза Хорна.
Фраза Хорна (Horn clause). Фраза Хорна — это либо факт, либо прави-
правило, либо запрос (цель).
Функтор (functor). Функтор — это имя и связанное с ним количество
аргументов структуры. Некоторые исследователи употребляют термин
"функтор" в менее строгом смысле для обозначения лишь имени струк-
структуры или имени предиката (см. работу [82]). Ученые, специализирующиеся
в области невычислительной логики, используют термин "функтор" по-
другому. Например, Ходжес в работе [45] называет логические соедини-
соединители "and" (и), "or" (или), "not" (не) функторами истинности. гс>"
Цель (goal).См.запрос. ;qr
и ;<f
II. ПОЛЕЗНЫЕ ПРОГРАММЫ 31
II. ПОЛЕЗНЫЕ ПРОГРАММЫ *J«;i ;.,
Различные процедуры л
% Изменить на обратный порядок расположения элементов списка.
% Метод №1: '
обр_порядок([С| L1J.L2) :- , г
обр_порядок (L1, Выход), j а., т*
присоединить (Выход, [С], L2). . j,f у
обр_порядок ([ ], [ ]). .Щ?Р$ fy &¦¦¦¦;"&¦'' :,;, .
%Метод№2: m^i,uf}psw , :_№
обр_порядок(Ы, [], L1).
обр_порядокAЛ, [XJL2], L3) :~
обрпорядок ([X ; L1], L2, L3). f' '', ¦
% Запрос ко второй версии процедуры сор^шляется СЙедутщЫ
% образом: *»*.
% i ?-обр_порядок([], [а, Ь, с], R). ' '",. -,' .
% число X возводится в степень Y, результат равен R.i«af«>s«/ f
степень@, 0, 0) :- ! .
степень(Х,0,1) :-!. • ,••'•'<*?
степень(X, 1,Х) :-!. uwc.fh {ЛЛПОШШйй .^
степень (X, Y, R) : - степень(X, Y, 1, R). ' ¦*
степень (А, 0, Окончат, Окончат) :— !.
степень (А, Р, Накопи, Окончат) : —
NPisP-1,
НовНакопл is Накопи * A,
степень (A, NP, НовНакопл, Окончат).
Процедуры сбора множества ответов и,
% ' тая
% F1NDALL — найти все ответы
% ? + - ' с«—
findall (Элемент, Запрос, _) :- j i
Запрос, '), .
взять_врем_ список(Список),
Присоединить (Список, [Элемент], Новощеок),
assert (врем_список(Новсписок)), j .
fail. .t-.j?'.I-.^--."
334 "" ' .-•¦'' ¦ * ПРИЛОЖЕНИЯ
findall(_, _,Список) : —
retract (врем _ список (Список)), ! .
взять_врем_список( [ ]) : —
по1(врем_список (_)), !. '
взять_врем_список (Список) :— lh
retract (врем _ список (Список)), !.
% спнеповтзнач—список неповторяющихся значений
% Данная процедура собирает все ответы на запрос, устраняя
% повторы.
% ? + -
сп_неповт_знач(Элемент, Запрос, Список) : —
Запрос,
взять_врем_ список (Список),
( элемент (Элемент, Список),
assert (врем _ список (Список)) -....
t -,.;: not (элемент (Элемент, Список)), ; -
assert (времсписок ([Элемент | Список ]))
), fail.
сп _ неповт _ знач (_,_, Список) : —
(времсписок(Список)), !.
Процедуры ввода-вывода низкого уровня
%
% ВВОДПОЛЯ/4 (Используется в приложении III)
%
% Выдать значения переменных Сообщ_подсказка и Умалчзнач
% (если таковое имеется) . Получить от пользователя Ответ.
% "Условие" — это некоторая разновидность запроса, в котором
% может участвовать переменная Ответ.
% Вычислить Условие; если оно потерпит неудачу, то снова
% запустить подпрограмму "вводполя".
% + ? +
ввводполя(Сообщ_подсказка, Ответ, Умалч_знач, Условие) :—'
write (Сообщ_ подсказка), nl,
( потгаг(Умалч_зчач),
write( ' ['), write (Умалч_ знач),
;•;¦¦ write(' ]'),
уаг(Умалчзнач) мл: :'
getO(C), .'*'¦' :
1Ь ПОЛЕЗНЫЕ ПРОГРАММЫ „_. 391
С = 10, % 10 — это код перевода строки » операционных
% систтемах UNIX и VMS • 'i--';^ '
Ответ = Умалч знач, ~ ._.,,;-_ >. ,;гр.:а
•¦¦'
:. с \== 10, ..,.; ifMe
вводсимволов ((С, Список),
rf ^ пате(Ответ,Спшсок) ^
Условие, ! . •
I % В предыдущем правиле "Гвводполя" подцель Условие потерпела,
% неудачу, предпринять нов}уЮ попытку:
вводполя(Сообщ_подсказк<а, Ответ, Умалчзнач, Условие) : —
! , вводполя(Сообщ_ подсказка, Ответ, Умалч_знач, Условие).
вводсимволовA0, []) :- ! . % 10 - код перевода строки
вводсимволов (С, [С ! Остаток ] )
getO(Cl), вводсимво;лов(С1, Остаток), !. , ..'
Программа "'отобразить_ состояние" •' :';
% ОТОБРАЗИТЬ СОСТОЯЩИЕ ' ¦ v :y
% Составная часть программы, описывающей мир кубиков (см.
% разд. 6.7). Аргументом процедуры "отобразить_состояние/1"
% является имя состояния. ГПрограмма печатает картину распопржеям
% кубиков для данного состояния. .•. .-.. •'..':•.¦'. *
отобразить состояние (Состсояние) :— , -V- :,tV; .« tl
% очистить экран дисплея: ^м^г,,^ |- :W*tM9 *
очистка _ экрана, ••¦ * '¦
% в строке 20 вывести слово "бтой*:"--''* " • -—" -"'«V« <
изобразить_столB0)„ -•.•¦;.•!¦ ¦¦•-• ¦: .¦¦•;»¦ vn-^м \'
% построить список в<сех кубиков, находящихся на столе:
findall (Кубик, послать, (Состояние, на (Кубик, стол) ), Список) ,
% начать вьшод изображений кубиков с позиции 10 строки 17:
первый слой (Состоящие, 10, 17, Список),
% оставить курсор под изображением:
курсор A, 22), ! .
% нарисовать слой кубиков, Находящихся непосредственно на столе:
первый_слой(Состояние, X, Y, [ ]).
первый_слой(Состояние, X, Y, [Кубик | Список ]) ^у
, % изобразить первый кубик: . ¦
У' к_кубику(Х,У,КубИк), ,.^viltj У • А"., -
р,, % передвинуться ввер\; .. t
ПРИЛОЖЕНИЯ
% вывести изображения всех кубико», стоящих на кубике
% "Кубик": ',.» ¦
... стек (Состояние, X, NY, Кубик), ». - . ^. ->¦
% сдвинуться вправо: '¦:•¦•¦
NX is X+ 10, , :
! , первый_слой (Состояние, NX, У.Список).
% вывести изображения всех кубиков, стоящих на кубике "Кубик":
стек (Состояние, X, Y, Кубик) :— ¦ '¦
% взять кубик (если таковой имеется), стоящий над
4j % кубиком "Кубик": t к „i
Gf| послать (Состояние, на (Сверху, Кубик)),
к кубику (X, Y, Сверху), > гд!в>> "*)¦
1э; : % передвинуться вверх:
!, стек (Состояние, X, NY, Сверху). \[ -п<.;
стек(_,_,_,_)• % над кубиком "Кубйк" нетдру**гО кубика.
к_кубику(Х, У, Кубик) :- ,.
курсор(X, Y), write(' '),
NYisY+1, '
курсор(Х, NY), write('l'),
write (Кубик), write ( 1'),
NNY is Y + 2,
курсор(Х, NNY), write(' -- '), ! . ^ н"'''ж> 'У '*
изобразить_стол(Y) :— .-^ ...i,i..f,
п, курсорA,У), ¦;. :
cf. write( -—•--. --.— .), ¦.-.•.¦•.¦
'}. ni, ¦' ¦¦¦-¦¦ "¦¦ .¦;¦ •;:; ¦ ¦ ¦ • ¦"¦•¦¦¦¦ ;
: write(' сто л '),
ni. ' .. ,;.. \':\
Экранно-ориентированная программа,
предназначенная для выполнения запросов к базе даииых
% ЗАПРОСЕД
% Эта программа вызывается при помощи запроса: ' ц *
% ! ?-запросбд(Имя).
% где "Имя" — это имя предиката.
% Для каждой опрашиваемой базы данных должен присутствовать
% факт "схема/2", первым аргументом которого является имя
% предиката, а вторым — список сообщений-подсказок (по одному
% на каждое поле).
II. ПОЛЕЗНЫЕ ПРОГРАММЫ Л, . .
% Примеры фактов "схема":
% Предикат Сообщения-подсказки " '
схема (служащий, ['Имя', 'Код', 'Должность', '
схема(отдел, ['Код','Название','Менеджер']).
% Примеры опрашиваемых баз данных: ,,
служащий (брайен, 100, оператор, 20000). ¦ ^ " ;i v' '
служащий (нэнси, 200, начальник, 71000). **
служащий(ральф, 100, менеджер, 71500). ,(-,
отдел A00, обработка данных, ральф). ( f
отдел B00, продажа, жб).
„f < ¦' Ч. ' »*t»,v ч i: j i .-
/о +
запросбд (Пред) : -
схема (Пред, Подсказки), . ч. «<-••).
чистка экрана, % очистить экрШК ,' rfi . „ , ^.,
курсорA,2), , ¦¦' . ^ .
repeat, > , .
цикл (Пред, Подсказки, Возврат), * ' ,.
| Возврат = х, ! . j. ...., i . f
% цикл: печатать все сообщения-подсказкичЛЮЖвЙЯ 25^
% Получить от пользователя параметры заЦЮ6Д,'а З^пманэмть
% процедуру "попытка запроса". •' %"
% + + - ¦ , ¦. _
цикл (Пред, Подсказки, Возврат) :— *"'*•.> 5
вывод_подсказокB5, 4, Подсказки), «?'ь к>:>,д
;¦: % пояснить, что появляется на экране: • S
;., курсорB5, 2), чистка_строки,
/• write('Введите параметры: '), *
ввод_параметров D0,4, Подсказки, Параметры),
% построить запрос:
'' ¦ Запрос = . . [Пред | Параметры],
! , попытка _ запроса (Пред, Подсказки, Параметры, Возврат,
Запрос).
% попытка_запроса: выполнить запрос, выдать ответ с позиции 40,
% а затем напечатать сообщение-подсказку для следующего действия.
попытка_запроса(Пред, Подсказки, Параметры, Возврат, Запрос) : —
Запрос, % разрешается возврат назад
% пояснить, что появляется на экране: V:
курсор B5, 2), чистка_ строки, write ('Ответы: '), ;•; . ,;¦;
вывод_ответов D0,4, Параметры), ' , ' .,
% подсказка для следующего действия: _ '-., -.. . ;
у, курсорB5, 23), чистка_строки, ' '''?"
write('m (еще ответы) с (изменить параметры) '),
write('x (выход)'),
вводполя (Ответ),
курсорB5, 23), чистка_ строки,
( Ответ = с,
цикл (Пред, Подсказки, Возврат)
>
Ответ = х, Возврат = х
% Если получен ответ, не равный с или х, то вернуться назад к
% приведенному выше Запросу.
% Запрос в предыдущей фразе "попытка запроса" потерпел неудачу,
% поэтому выполнить следующие действия:
попытка_запроса (Пред, Подсказки, _, Возврат, _) :—
% подсказка для следующего действия: * ¦
курсорB5, 23), чистка_строки, '
к - write( Ответов (больше) нет.'), '
write ('с (изменить параметры) х (выход)'), ¦''
вводполя (ответ), riu't "¦
курсорB5, 23), чистка_строки, ^p:t'-J?4'"
( Ответ = х, Возврат = х * , п'нг-- ¦
* % если Ответ не равен х: t, ,y- ¦(;,,.,
ккг" цикл (Пред, Подсказка, Возврат) ..*¦' ,
вывод_подсказок(_, _, [ ] ).
вьшод_подсказок(Х, Y, [Подсказка i Подсказки] ) :— '
курсор(Х, Y), write (Подсказка), чистка строки, ;
NY is Y + 2, % передвинуться вниз на две строки '„'
!, вывод_подсказок(X, NY, Подсказки).
вывод_ответов(_, _, [ ] ). ,f ! ^
Вьшод_ответов(Х,У, [Ответ 1 Ответы ]) :- и « <;н мглы t ..
rfH* курсор (X,Y), чистка_строки, ;™
. " % ничего не делать, если переменная "Ответ" не конкретвявро-
f! %вана: •'¦"
с"- (уаг(Ответ); write (Ответ)),
. ,'?'. NYisY+2, % сдвинуться вниз на две строки
>''ь ' . !, вывод_ответов(Х, NY, Ответы). "
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 339
ввод_параметров (_, _, [], [ ] ).
ввод_параметров (X, Y, [Подсказка ] Подсказки],
[Параметр | Параметры] ) : —
курсор (X, Y),
% если первым символом будет возврат каретки, то переменная
% "Параметр" останется неконкретизированной:
вводполя(Параметр),
NY is Y + 2, % сместиться вниз на две строки
! , ввод_параметров (X, NY, Подсказки, Параметры) .
% позиционирование курсора на терминале, совместимом с
% терминалом vt 100:
курсор (X, Y) :-
putB7), %
put(91), %
write(Y),
putE9), %
write(X),
putG2). %
% очистить экран
чистка экрана : —
курсор A, 1)
putB7), %
put(91), %
put G4). %
escape
[
;
H
,
escape
[
J
% чистка до конца строки
чисткастроки :-
putB7), % escape
put(91), % [
putG5). % К
% Текст процедуры "вводполя/1" см. в разд. 3.9 .
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР
ПРОГРАММА ПЛАНИРОВАНИЯ РАБОТЫ ЗАВОДА
Ситуация
Представьте себе, что Вы — менеджер небольшого промышленного
предприятия. Завод выполняет заказы на изготовление определенных ви-
видов продукции. Типичный цикл изготовления продукции состоит из обра-
обработки изделий четырьмя типами производственных установок, но может
потребоваться и специальная доводка изделий на одном или более
типов установок.
ЗЙ ПРИЛОЖЕНИЯ
В любой смене имеется группа операторов, обеспечивающих работу
установок. На некоторых установках может работать только определенное
количество операторов. Операторы работают по гибкому графику выхода
в смену, так что в любой конкретный день на работе может присутствовать
различное количество операторов. Иногда операторы раньше уходят с
работы.
В обязанности мастера входит планирование использования ресурсов
завода (т.е. операторов и установок) с тем, чтобы эффективно выполнить
обработку всех подлежащих изготовлению изделий. Некоторые производ-
производственные задания нужно выполнить как можно скорее, в то время как
изготовление других видов продукции можно отложить до того времени,
когда не останется никаких других заказов, подлежащих срочному выпол-
выполнению. Как менеджер Вы должны обеспечить то, чтобы мастер использо-
использовал установки с полной загрузкой. Вы должны также постоянно иметь
точное описание ресурсов (т.е. затрат), требуемых для выполнения заказа
по любому виду продукции. После тщательного анализа ситуации Вы ре-
решаете, что можно значительно повысить производительность труда мастера,
если разработать компьютерную программу, которая поможет ему опти-
оптимально планировать распределение ресурсов в течение смены. Практичес-
Практическая польза от такой программы, однако, будет явно зависеть от того, на-
насколько эта программа будет соответствовать привычному стилю работы
мастера. Если мастеру будет трудно пользоваться программой, то он, воз-
возможно, либо просто будет игнорировать ее, либо не будет придавать ей
должного значения. Следовательно, нужно уделить особое внимание ин-
интерфейсу данной компьютерной программы с пользователем, чтобы быть
уверенным, что мастер будет пользоваться этой программой для выполне-
выполнения всех тех действий, которые он производит сейчас при планировании
вручную. Для того чтобы спроектировать интерфейс с пользователем, не-
необходимо внимательно понаблюдать за тем, как работает мастер.
Как работает мастер
Как правило, мастер приходит на работу не менее чем за час до начала
смены. Он начинает с сортировки видов работ, которые нужно выполнить,
включая те производственные задания, которые были лишь частично выпол-
выполнены во время предыдущей смены. Он должен отобрать совокупность
заданий, которые подлежат выполнению в данную смену, с учетом важ-
важности выполнения каждого задания. Он проверяет рабочее состояние уста-
установок на этот день, а также смотрит, кто из операторов, как предпола-
предполагается, должен появиться на работе. Он сравнивает различные варианты пла-
планов, в которых фигурируют заказы, станки и операторы, н выбирает план,
который обеспечивает выполнение за время смены большей части необ-
необходимой работы. Производительность установок обычно зависит от того,
сколько операторов работает за ними, поэтому "тонким" местом планиро-
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР , , 341
вания является распределение и перераспределение операторов во время
смены для работы за разными установками.
К моменту прибытия операторов на работу мастер уже выработал об-
общий план. Он выдает каждому оператору индивидуальный план. Если во
время смены случится что-то непредвиденное (сломается установка или
оператор раньше отпросится с работы), то мастер должен будет составить
другой план, позволяющий наилучшим образом использовать имеющиеся
ресурсы.
Прототип программы
Вы решаете, что начать Вашу работу нужно с создания прототипа прог-
программы планирования, предназначенной для мастера. Основное назначение
прототипа состоит в том, чтобы разработать интерфейс, которым мастер
сможет пользоваться на практике, и чтобы проверить делаемые мастером
предположения о производительности установок. В производственной вер-
версии программы должна быть предусмотрена работа при большом разно-
разнообразии ситуаций, включая разные типы изделий, различные сочетания
установок и т.д. Однако для того, чтобы как можно скорее создать работо-
работоспособный прототип программы, представляется целесообразным при
выборе функциональных возможностей прототипа ограничиться некоторым
подмножеством функциональных возможностей производственной прог-
программы. В связи с этим прототип сможет планировать изготовление лишь
таких видов продукции, для которых требуется последовательная обра-
обработка на четырех установках, и не будет учитывать необходимость допол-
дополнительной доводки изделий на некоторых установках. Приведем далее
описание прототипа программы.
Представление ситуации
Разрешающая способность прототипа программы по времени состав-
составляет один час. Это означает, что мастер может изменять распределение зада-
заданий и операторов по установкам только один раз в час. Данное упрощение
позволит быстрее написать работоспособный прототип программы. В реаль-
реальной программе, предназначенной для планирования производственного
процесса, может потребоваться более высокая разрешающая способность
по времени, равная, скажем, четверти часа.
Прототип рассчитан на планирование работы только одной смены за
день. Эта смена начинается в 8 часов утра (в программе это представлено
как "8") и продолжается до часа дня (в программе это представлено как
3"). Каждое производственное задание снабжается уникальным иденти-
идентификатором, в качестве которого можно употребить наименование
заказчика.. Перемещение продукции по заводу от установки к установке
отслеживается при помощи названий установки и накопителя. Накопитель—
это место, где собирается продукция, обработанная одной установкой, в
342 <да ПРИЛОЖЕНИИ
Г Накопитель 1 J (Начало)
Установка «алыра>>
( ^ Mti
Накопитель 2 J , ),.
Установка «бета»
? Накопитель 3 )
Остановка «гамма»
С Накопитель 4 J
Остановка «дельта»
С Накопитель 5 j (Коней,)
Рис. III. 1
ожидании обработки на следующей установке. Установки носят следующие
названия: альфа, бета, гамма и дельта. Накопители обозначаются цифрами
1, 2, 3, 4 и 5. Весь производственный цикл завода схематически изображен
на рис. III. 1.
Количество продукции измеряется в изделиях, а производительность
установки — в изделиях в час. Предположим, что к восьми часам утра
в накопителе 2 имеется 15 изделий, относящихся к прозводственному за-
заданию "консолидейтед" (наименование заказчика), и что производитель-
производительность установки бета равна двенадцати изделиям в час. Тогда к девяти ча-
часам в накопителе 2 останется 3 изделия заказа "консолидейтед", а в нако-
накопитель 3 поступит 12 изделий этого заказа.
Заказы
Информация о том, что в конкретном накопителе имеется некоторое
количество изделий, изготавливаемых по определенному заказу, представ-
представляется при помощи следующего факта:
% Час Накопитель Идентификатор Изделий
заказ (8, 2, консолидейтед, 15).
Этот факт гласит, что в 8 часов утра в накопителе 2 имеется 15 изделий за-
заказа "консолидейтед". В начале смены планирующая программа анализиру-
анализирует все факты "заказ", имеющиеся в текущей программе, и вырабатывает
Ш. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР ;К„ 343
план того, как следует в течение смены осуществлять выполнение этих
заказов. После того как масгер одобрит план, он сможет далее модели-
моделировать при помощи данной программы производственный процесс завода
с интервалами времени продолжительностью в один час. (В производствен-
производственной программе предсказанный объем выработки продукции всегда будет
сверяться с реальным объемом.) После того как планирующая программа
смоделирует производство продукции за один час, в нее добавляются
новые факты "заказ", показывающие положение каждого заказа к концу
этого часа. Предположим, что в течение часа, начинающегося в 8 утра,
производительность установки бета равна двенадцати изделиям в час. Тогда
после обработки планирующей программой восьмого часа в нее добавятся
два новых факта "заказ", показывающие положение заказа "консолидей-
тед" к девяти утра. Эти факты таковы:
% Час Накопитель Идентификатор Изделий 'lj|l|: - <^;
заказ(9, 2, юонсолидейтед, 3). - ... Н.с» *-;л «
заказ(9, 3, консолидейтед, 12). • ¦'•'"'*• -:'; • •
4 ^«rti:; >•< ¦ '¦'¦ '¦• ¦..•¦•¦ ¦. .vi-
Операторы '.
Если оператор приходит на работу к началу смеяы, то В
|добавляется нижеследующий фаяст: "' '" •
% Приход Имя ..-. .;.' ¦ t\ .{ ,', ,,.',.,"/
оператор(8, джек). -л- ./!;' [ ч'..,,'>.", "".''"..-'.„^ 'TltZl
Г1
Если оператор должен уйти до окончания смены, то в базу данных дол-
должен быть добавлен нижеследуюиций факт "опровергнуть", запрещающий
планирование работы данного огеератора после его ухода:
% Джек уходит в 11.00 .'¦."'•tiii ''.''¦' - '• »*' f"-l!-
опровергнутьA1,оператор(_-,джек)). *.№?'¦¦ ¦¦¦¦'¦"' jCiiiflf•¦ ть
Мастер должен знать, сколько ошераторов присутствуют на работе в тече-
течение любого часа смены. Приведенная выше форма фактов "оператор"
позволяет воспользоваться механизмом наследования из гл. 7 для того,
чтобы отслеживать количество операторов, находящихся на работе в тече-
течение каждого часа смены. Значейшя часов связываются друг с другом с
помощью базы данных "порожденше", имеющей следующий вид:
^ порождение (9, 8).
К- порождение A0,9). "',","'.'-'.' ,,, '
344 'UWH4)i К»Ы ПРИЛОЖЕНИЯ
Нижеследующее правило позволяет установить общее число операто-
операторов, находящихся на работе в течение любого заданного часа смены:
% построить список всех присутствующих операторов ('а ш'п
макс_операторов (Время, Количество) : —
% построить список
% для часа "Время"
findall (X, послать (Время, оператор(Х)),* iJ
si'... Список), ' '
в* ' r length (Список, Количество) .
ж»"5 Производительность установок
Каждая установка обладает определенной производительностью, выра-
выраженной в изделиях в час. Производительность зависит от количества опера-
операторов, приставленных к установке. Например, производительность уста-,
новки дельта составляет восемь изделий в час на каждого прикрепленного
к ней оператора. Эту информацию можно представить в виде нижеследую-
нижеследующего простого правила:
% Название Операторы —
х, производит—установки (дельта, Количество, Производительность):—
Производительность is Количество * 8.
Однако планирующая программа иногда должна проверять производи-
производительность установки при различных распределениях операторов. При ис-
использовании приведенного правила "производит_установки" возникает
проблема, заключающаяся в том, что если переменная «Количество»
не будет конкретизирована, то при обработке подцели "is" возникнет
ошибка. В приводимой ниже версии правила "производит_установки"
генерируется возможное значение переменной «Количество», если эта
переменная не конкретизирована. При этом генерируемое значение не пре-
превышает общего числа операторов, работающих в данную смену. В правило
добавлен дополнительный аргумент, несущий информацию об общем
числе операторов. Для генерирования значений переменной «Количест-
«Количество )) используется правило "ген_чисел".
% + + ? ..'
,,а производит_установки (дельта, МаксОпер, Количество, _ ,
% iW Производительность) :-
( var (Количество),
ген_чисел (МаксОпер, Количество)
nonvar (Количество)
)
* ¦ • 1
"л * f/
I
обработка _ г^*"^
l_ '\
я"
KOFP-Операторов
выдать посл_
накопи тели
выдать.оп_путь
обработка часа
добавить^работу
план - смены
; - *
1—
1
/г
выд,эть_список _
накопит
выдать список_
операторов
обработка-
накопителя
распределение
.:; ..."
\
i
корр_списка _опер
распределение
)
1
V
накопит К
индекс списка
накопителей
Рис. Ш.2
от-накопит_ к_
накопит
макс_
операторов
распределить-
операторов
накопитель
заказ
/
Л
\
\
—
от_заказа_
к_заказу
произаодит_уст
найти
установку
оператор
наименование-
установки
3
9
S
ж
я
я
i \
- ?
IT; .¦;* I'
< u. ).i 4° 8 изделий/час/оператор: ¦ " ,, If
Производительность is Количество ¦ 8
% сгенерировать целое число N из диапазона от 1 до Мак? \ -
% включительно: ,|;"<ч'-у '- ¦
* + , ; ¦ : : = , • ;, U ' '¦
ген_чисел (Макс, N) : — ¦ it/, ¦ . j. Г ¦" ! f '-¦'!
ген_чиселО(Макс, 1,N). : ' ... ; <. : ^' !..,.,!'
1 % + + - ; „;:;,; '¦/.';: ^' " \
ген_чиселО(Макс, Начало, Начфф). : '" :;
¦ ген_чиселО(Макс, Начало, N):^te fV.r.::. ,'-;j
НовНачало is Начало + 1, ! I ? J. . •... j *-^'>u"-c-*j».i.;':m :
НовНачало = < Макс, ' , .; -
ген_чиселО (Макс, НовНачало, N). - < " . . .
Если переменная «Количество» не была конкретизирована в запросе к
правилу "производит—установки", то за счет поиска с возвратом правило
"ген_чисел" сгенерирует все возможные значения этой переменной из
диапазона от 1 до << МаксОпер )>.
Структура программы
Взаимосвязь компонент планирующей программы показана на
рис. Ш.2 (Структура планирующей программы). Мастер начинает работу
с программой запросом к процедуре "старт", аргументом которой являет-
является первый час смены. Процедура "старт" позволяет мастеру добавлять но-
новые производственные задания. Затем данная процедура вызывает рекур-
рекурсивную процедуру "обработка_смены", играющую роль основного интер-
интерфейса программы с пользователем. Вначале процедура "обработка_смены"
предоставляет мастеру сокращенное меню выбора действий высокого уров-
уровня. Одно из этих действий, «план », позволяет построить план работы
целой смены. Сначала мастер должен построить план, так как при выполне-
выполнении любых других действий потребуется наличие текущего плана. Если
план не будет построен, то программа не допустит выполнения мастером
каких-либо других действий. Компоненты программы можно разбить на
несколько категорий в соответствии с табл. III.1.
Примеры сеансов работы с программой
Ниже описьшаются два сеанса работы мастера с прототипом програм-
программы и даются подробные пояснения действий программы и мастера. К на-
началу каждого сеанса на работе присутствуют пять операторов и имеются
два заказа, подлежащие выполнению:
% Час Накопитель Идентификатор Изделий
заказ(8, 1, доу, 18). , :'."*.'; "
заказ(8, 1, макгроу, 25).
}11. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР
347
Таблица III. 1
Категория
¦w
Процедуры
интерфейс с пользователем
старт
обработка_смены
план_смеиы
обработка_часа
добавить_работу
вывод
вьщать_посл „накопители
выдать_оп_путь
корректировка
корр_плана
корр_операторов
планирование
.*(».
¦Г Mi
найти_оптим ал ьное_распре деление
найти_распределеиие
распре делить_операторов
от_накопит_к_накопит
от_заказа_к_заказу
Обратите внимание на то, что интерфейс с пользователем всегда обес-
обеспечивает возможность выбора принимаемого по умолчанию ответа на
поставленный вопрос. Этот ответ высвечивается на экране дисплея в
квадратных скобках и располагается под вопросом. Если мастер захочет
воспользоваться ответом, принимаемым по умолчанию, то он должен на-
нажать на клавишу возврата каретки. (См. текст процедуры "вводполя/4"
из приложения II — там показано, как это делается.) Для большинства
вопросов имеется ограниченное число ответов. Если мастер введет
некорректный ответ, то вопрос будет задан повторно. Для некоторых вопро-
вопросов выводится список допустимых ответов. Заметьте также, что вопросы
наиболее высокого уровня интерфейса с пользователем располагаются на
экране, начиная с левого края поля вывода, а вопросы более низких уров-
уровней вьшодятся с соответствующим отступом от края.
Сеанс 1 *)
Нужно ли вводить новое задание'! (да или нет)
[нет] % пользователь нажимает клавишу возврата ка-
% ретки, выбирая принятое по умолчанию зна-
% чение "нет"
*) Действительный формат выводимой информации будет иемного отличаться от
риводимого здесь. - Причем, пер.
(Час равен 8)
(требуется новый план)
команда"! ('план','обработка','помощь'-для вывода списка
возможных команд)
[план] % пользователь нажимает клавишу возврата
% каретки
Построение плана...
Далее программа в течение некоторого времени вычисляет план. После
завершения составления плана выводится таблица распределения операто-
операторов по установкам на всю смену, а также таблица, показывающая положе-
положение каждого заказа к моменту окончания смены.
- Нижеследующее распределение операторов
Час Уст. On. Уст. On. Уст. On. Уст. On.
8
9
10
11
12
альфа
альфа
альфа
альфа
альфа
5 бета
3 бета
1 бета
0 бета
0 бета
0
2
2
1
0
гамма
гамма
гамма
гамма
гамма
0
0
2
2
2
дельта
дельта
дельта
дельта
дельта
приведет к такому состоянию заказов
к 13 часам:
Накопи-
Накопитель
1
2
3
4
5
Идентифи-
Идентификатор
макгроу
макгроу
макгроу
макгроу
макгроу
Кол-во
0
0
0
0
25
Идентифи-
Идентификатор
доу
доу
доу
доу
доу
0
0
0
2
3
К*'" !'¦¦- IVV -I * ;W i •' ','• ¦
Кол-во Иденти- К
фикатор
0
0
0
3
15
Ко/Ыо
введите' принять',если план подходит, или
' корректировка', если план нужно изменить
[принять] % пользователь нажимает на клавишу
% возврата каретки
(Час равен 8) ;
команда! ('план', 'обработка',' помощь' - для вывода списка
возможных команд)
[обработка] % пользователь нажимает на клавишу воз-
(!• % врата каретки
Мастер нажал на клавишу возврата каретки, что соответствует выбору
принимаемого по умолчанию ответа « обработка ». Тем самым мастер дал
программе указание смоделировать изготовление продукции в течение пер-
первого часа смены (с 8 до 9 часов утра). В программу добавляются новые
факты, показывающие положение каждого заказа к 9 часам утра.
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 349
(Час равен 9)
команда! ('план', 'обработка', 'помощь' — для вывода списка
возможных команд) ~
[обработка] помощь
Возможные команды:
план (составить план на оставшуюся часть смены)
обработка (смоделировать работу за следующий час)
помощь
показать работу (повторно вычислить и показать
текущее состояние заказов)
показать операторов (текущее распределение операторов)
показать план (план на оставшуюся часть смены)
конец дня
(Час равен 9)
команда! ('план', 'обработка', 'помощь' — для вывода списка
возможных команд)
[обработка] показать работу
Заказы на 9 часов
Никопи- Идентифи- Кол-во Идентифи- Кол-во Идентифи- Кол-во
тель катор катор катор
1 макгроу 0 доу 18
2 макгроу 25 доу О
3 макгроу 0 доу О
4 макгроу 0 доу О
5 макгроу 0 доу О
Нужно ли вводить новое задание! (да или нет)
[нет] % пользователь нажимает на клавишу возврата
% каретки
(Час равен 9)
команда! (план , 'обработка , 'помощь - для вывода списка
возможных команд) ¦ .;,
[обработка] показать операторов ¦-> г '
Операторы в 9 часов • *j». , •
альфа 3 бета 2 гамма 0 дельта 0 ?>¦*¦ «
Добавить или удалить операторов!(добавить, удалить, продолжить)
[продолжить] % пользователь нажимает клавишу
% возврата каретки
Выше показано, что мастер захотел просмотреть состояние заказов
и распределение операторов в 9 часов утра. Ниже мастер нажимает на
клавишу возврата каретки, чтобы смоделировать обработку изделий в
течение оставшихся до конца смены часов.
350 ПРИЛОЖЕН^
(Час равен 9)
команда! (план', 'обработка', 'помощь' - для вывода списка '}
возможных команд) '
[обработка] % пользователь нажимает на клавишу
% возврата каретки
(Час равен 10)
команда! ('план', 'обработка', 'помощь' - для вывода списка '
возможных команд) ¦$,¦,
[обработка] -% пользователь нажимает на клавишу 1Т
% возврата каретки . щ
(Час равен 11)
команда! ('план', 'обработка', 'помощь' - для вывода списка
возможных команд)
[обработка] ш, % пользователь нажимает на клавишу
% возврата каретки
(Час равен 12)
команда! ('план', 'обработка', 'помощь' - для вывода списка
возможных команд)
[обработка] % пользователь нажимает на клавишу
% возврата каретки
Конец смены в час 13. *в
Состояние заказов:
Накопи- Идентифи- Кол-во Идентифи- Кол-во Идентифи- Кол-вв
тель каюр каюр катор
1 макгроу 0 доу 0
2 макгроу 0 доу 0 ;
3 макгроу 0 доу 0
4 макгроу 0 доу 3
5 макгроу 25 доу 15
При достижении конца смены программа автоматически печатает состояние
заказов. Поскольку мастер не добавлял новых заданий во время выпол-
выполнения программы и не изменял распределение операторов, итоговое
состояние заказов оказалось точно таким же, как зто было предсказа-
предсказано при первоначальном составлении плана.
Во время второго сеанса работы с прототипом мастер изучает не-
некоторые другие возможности программы, такие как добавление новых
производственных заданий в середине смены, добавление нового опера-
оператора в середине смены и корректировку распределения операторов.
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 351
Сеанс 2 ''¦¦¦'¦
(Час равен 8)
Нужно ли вводить новое задание! (да или нет) ,.
[нет] % пользователь нажимает На клавишу
% возврата каретки
(Час равен 8) .**ч,' '*»-
(требуется новый план) *" ^
команда? ('план', 'обработка', 'помощь' - для вывода списка.,^'
возможных команд)
[план ] % пользователь нажимает на клавишу
% возврата каретки
Построение плана... '-i
Нижеследующее распределение операторов '•'»"*¦*'¦¦**¦ •
Час Уст. On. Уст. On. Уст. On. Уст. On.-s-"'-lt----
8 альфа 5 бета 0 гамма 0 дельта О
9 альфа 3 бета 2 гамма 0 дельта 0 ' , < •>
10 альфа 1 бета 2 гамма 2 дельта 0 д,,.-
11 альфа 0 бета 1 гамма 2 дельта 2 ,;i&
12 альфа 0 бета 0 гамма 2 дельта 3 ,.,.^
приведет к такому состоянию заказов к 13 часам:
Накопи- Идентифи- Кол-во Идентифи- Кол-во Иденти- Кол-во
телъ катор катор фикатор
1 макгроу 0 доу О
2 макгроу 0 доу О
3 макгроу 0 доу О
4 . макгроу 0 доу 3 *
5 макгроу 25 доу 15 '^
введите 'принять', если план подходит, или
'корректировка!', если план нужно изменить
¦ [принять] % пользователь нажимает на клавишу
:; % возврата каретки
(Час равен 8) ^ , , ,
I команда! (план', 'обработка'', 'помощь' - для вывода списка ,-¦¦,¦<
г возможных команд) ..¦ «ч,д
6 [обработка] % пользователь нажимает на клавишу- .i,^-
F % возврата каретки ,<;.ла .-
I (Час равен 9) ^ ^ ^ • ^ v«.
команда? ('план', 'обработка', 'помощь' - для вывода списгШ'Х:
возможных команд) j gf\
[обработка] помошчь л
Вы ошибочно ввели помошчь I
352 ПРИЛОЖЕНИЯ
Правильные команды:
план
обработка
помощь
показать работу
показать операторов
показать план
конец дня
Обратите внимание на то, что программа обнаружила неправильно
набранную команду "помощь", указала мастеру на ошибку и выдала спи-
список правильных команд. После выполнения этих действий программа
повторяет вопрос:
команда! (план , 'обработка', 'помощь' - для вывода списка
возможных команд)
[обработка] помощь . ";*'
. %. ¦ ¦
Возможные команды: ^ .
план (составить план на оставшуюся часть смены) <\-t
обработка (смоделировать работу за следующий час) ¦
помощь ?д
показать работу (повторно вычислить и показать
текущее состояние заказов)
показать операторов (текущее распределение операторов)
показать план (план на оставшуюся часть смены)
конец дня
(Час равен 9) v
команда? ('план', 'обработка', 'помощь' - для вывода списка %
возможных команд) /
[обработка] показать работу
Заказы на 9 часов
Накопи- Идентифи- Кол-во Идентифи- Кол-во Идентифи- Кол-во
тель катор катор катор
1
2
3
4
5
макгроу
макгроу
макгроу
макгроу
макгроу
0
25
0
0
0
доу
доу
доу
доу
доу
18
0
0
0
0
Нужно ли вводить новое задание! (да или нет)
[нет] да
Введите наименование заказа или слово "конец"
[конец] цито **'¦
HI. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 353
Количество изделий"!
[0] 12
Заказ добавлен
Введите наименование заказа или слово "конец"
[конец] % пользователь нажимает на клавишу
% возврата каретки
Заказ был добавлен, так как существовал текущий план
Строится новый план ...
После того как мастер вводит команду « показать работу », кото-
которая относится к верхнему уровню меню команд, программа отображает
положение заказов на текущий час и предоставляет мастеру возмож-
возможность добавить новые производственные заказы. В данном случае как раз
перед девятью часами утра появился срочный заказ, который носит наи-
наименование "цито" и состоит из двенадцати изделий. Поэтому мастер
вводит сведения о новом заказе. Программа выясняет, что поступила
новая работа, и поэтому автоматически решает построить новый план.
Заметьте, что в приведенном ниже плане новый заказ имеет приоритет
над имевшимися ранее заказами.
Нижеследующее распределение операторов
Час Уст. On. Уст. On. Уст. On. Уст. On.
9 альфа 4 бета 1 гамма 0 дельта О
10 альфа 2 бета 1 гамма 2 дельта О
11 альфа 0 бета 1 гамма 2 дельта 2
12 альфа 0 бета 1 гамма 2 дельта 2
приведет к такому состоянию заказов к 13 часам:
Накопи- Идентифи- Кол-во Идентифи-Кол-во Идентифи-Кол-во
телъ катор каюр
1 цито О макгроу
2 цито О макгроу
3 цито 0 макгроу
4 цито 0 макгроу
5 цито 12 макгроу
введите 'принять', если план подходит, или
'корректировка , если план нужно изменить
[принять] % пользователь нажимает на клавишу
% возврата каретки
{Час равен 9)
команда, (план , 'обработка', 'помощь — для вывода списка
возможных команд)
[обработка] % пользователь нажимает на клавишу
% возврата каретки
! 2 Лж Мя ттгтяг
0
0
0
7
18
катор
доу
доу
доу
доу
доу
0
0
10
8
0
354 ПРИЛОЖЕНИЯ
{Час равен 10)
команда! {'план', 'обработка', 'помощь' - для вывода списка
возможных команд)
[обработка] % пользователь нажимает на клавишу
% возврата каретки
{Час равен 11)
команда! {'план', 'обработка', 'помощь' - для вывода списка
возможных команд)
[обработка] показать операторов
Операторы в 11 часов
альфа 0 бета 1 гамма 2 дельта 2 •¦¦<
Добавить или удалить операторов! {добавить, удалить, продолжит)
[продолжить] добавить
Введите имя оператора или слово 'конец' для продолжения работы
[конец] мери
Оператор добавлен
Введите имя оператора или слово 'конец' для продолжения работы
[конец] % пользователь нажимает на клавишу
% возврата каретки
После того как мастер вводит команду «показать операторов», от-
относящуюся к верхнему уровню меню, программа выводит текущее рас-
распределение операторов по установкам и предоставляет мастеру возмож-
возможность добавить новых операторов или удалить имеющихся. В данном слу-
случае как раз перед одиннадцатью часами пришел оператор по имени Мери.
Мастер внес ее имя в базу данных. Ниже показано, что мастер строит
новый план перед тем, как продолжить работу. Обратите внимание, на-
насколько больше работы будет сделано к концу смены в результате то-
того, что будут работать шесть операторов, а не пять.
{Час равен 11)
команда! (план , 'обработка , 'помощь - для вывода списка
возможных команд)
[обработка] план
Нижеследующее распределение операторов
Час Уст. On. Уст. On. Уст. On. Уст. On.
11 альфа 0 бета 2 гамма 2 дельта 2
12 альфа 0 бета 1 гамма 2 дельта 3
приведет к такому состоянию заказов к 13 часам:
Накопи- Идентифи-Кол-во Идентифи-Кол-во Идентифи- Кол-ва
телъ каюр катор катор
1 цито 0 макгроу 0 доу О
2 цито 0 макгроу 0 доу О
0
7
iff
доу
доу
доу
5
13
0
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 355
3 цито 0 макгроу
4 цито 0 макгроу
5 цито 12 макгроу
введите 'принять', если план подходит или
'корректировка', если план нужно изменить
[принять] корректировка
По какой-то причине мастера не устраивает автоматически вырабо-
выработанный план, поэтому он решает изменить план. В режиме корректи-
корректировки программа показывает положение заказов и распределение опе-
операторов для каждого часа, оставшегося до конца смены, причем мастер
может изменить распределение операторов по установкам. Для часа,
начинающегося в 11 часов утра, мастер направляет на установку бета
одного оператора вместо двух, а на установку дельта — трех операто-
операторов вместо двух. Для часа, начинающегося в 12 часов дня, мастер со-
согласен с имеющимся распределением операторов.
Планируемая работа завода на 11 часов:
Накопи- Идентифи-Кол-во Идентифи-Кол-во Идентифи-Кол-во
телъ катор катор катор
1 цито 0 макгроу 0 доу О
2 цито 0 макгроу 7 доу 18
3 цито 12 макгроу 3 доу О
, 4 цито 0 макгроу 15 доу О
> 5 цито 0 макгроу 0 доу О
I Текущее распределение операторов:
t альфа 0 бета 2 гамма 2 дельта 2
Установка: альфа Количество операторов:
[0] % пользователь нажимает на клавишу
% возврата каретки
Установка: бета Количество операторов:
[2]\
Установка: гамма Количество операторов:
[2] % пользователь нажимает на клавишу
% возврата каретки
Установка: дельта Количество операторов:
[2]3
Планируемая работа завода на 12 часов:
Накопи- Идентифи-Кол-во Идентифи-Кол-во Идентифи-Кол-во
тель катор катор ' катор
1 цито 0 макгроу 0 доу О
2 цито 0 макгроу 0 доу 10
12*
356 ПРИЛОЖЕНИЯ
3 цито 0 макгроу 7 доу 8
4 цито 12 макгроу 3 доу О
5 цито 0 макгроу 15 доу О
Текущее распределение операторов:
альфа 0 бета 1 гамма 2 дельта 2
Установка: альфа Количество операторов:
[0] % пользователь нажимает на клавишу
% возврата каретки
Установка: бета Количество операторов:
[1 ] % пользователь нажимает на клавишу
% возврата каретки
Установка: гамма Количество операторов:
[2] % пользователь нажимает на клавишу
% возврата каретки ;
Установка: дельта Количество операторов: - '¦'"_
[3] % пользователь нажимает на клавишу
% возв рата каретки
Планируемая работа завода на 13 часов (конец):
Накопи- Идентифи- Кол-во Идентифи-Кол-во Идентифи- Коа-во .»¦
тель
1
2
3
4
5
катор
цито
цито
цито
цито
цито
0
0
0
0
12
катор
макгроу
макгроу
макгроу
макгроу
макгроу
0
0
0
7
18
катор
доу
доу
доу
доу
доу
0
0
10
8
0
В конце сеанса корректировки программа повторно вычисляет и
выдает на экран дисплея ожидаемое положение заказов к концу смены.
Заметьте, что ввиду того, что мастер изменил распределение операторов,
вычисленное программой, в соответствии с новым планом будет выпол-
выполнен меньший объем работы, чем при использовании автоматически сге-
сгенерированного плана. Если мастер останется недоволен результатами
корректировки плана, то он может снова скорректировать его или по-
построить новый план автоматически.
(Час равен 11)
команда? (план1, 'обработка', 'помощь' - для вывода списка
возможных команд)
[обработка] % пользователь нажимает на клавишу
% возврата каретки
Ш. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 357
(Час равен 12)
команда! (план , 'обработка', 'помощь - для вывода списка
возможных команд)
[обработка] % пользователь нажимает на клавишу
% возврата каретки
Конец смены в час 13.
Состояние заказов:
Накопи- Идентифи-Кол-во Идентифи- Кол-во Идентифи-Кол-во
тель
1
2
3
4
5
катор
цито
цито
цито
цито
цито
0
0
0
0
12
катор
макгроу
макгроу
макгроу
макгроу
макгроу
0
0
0
7
18
каюр
доу
доу
доу
доу
доу
0
0
10
8
0
Пользование программой
Структура программы позволяет мастеру опробовать различные ва-
варианты планов. К примеру, он мог бы построить несколько планов на це-
целую смену, в которые были бы или не были бы включены заказы с низким
приоритетом. Мастер также мог бы менять порядок расположения заказов
в базе данных (порядок расположения заказов определяет их приоритет).
Мастер мог бы попытаться варьировать количество операторов. Он может
провести эксперименты с добавлением новых производственных заданий
в середине смены или с добавлением и удалением операторов в течение
смены.
Постепенное уточнение
Во время тестирования прототипа будут собираться сведения о факти-
фактической производительности установок в различных условиях, эти данные
будут сравниваться с результатами, предсказываемыми программой.
Приведенная база данных "производит_установки" является лишь ап-
аппроксимацией реального положения дел, она будет постепенно уточняться
по мере накопления более точных данных.
Программа
Алгоритм планирования
Алгоритм составления оптимального плана стоит рассмотреть подроб-
подробно. Процедура "найти_оптимальное_распределение" является деклара-
декларативным интерфейсом между планирующей компонентой и остальной частью
программы. Распределение операторов по установкам на целую смену
описывается переменной «ОпПуть». С этой переменной связана перемен-
переменная «НакопПуть», описывающая положение заказов в накопителях во
358 ПРИЛОЖЕНИЯ
время смены. Информация, которую несет переменная «НакопПуть»,
получается в результате распределений, описываемых переменной
«ОпПуть». Переменная «ЗакНакопители » (итоговый список накопите-
накопителей) является последним элементом списка « НакопПуть » и она описы-
описывает положение всех заказов в конце смены. Процедура "индекс_спис-
ка_накопителей" вычисляет значение переменной «ЗакНакопители»
и присваивает ей значение индекса. Чем больше работы будет сделано
к концу смены, тем выше будет значение индекса.
Процедура "найти оптимальное распределение"
Процедура "найти_оптимальное_ распределение" начинает свою рабо-
работу с добавления факта "оптимальный план" со значением индекса, рав-
равным нулю. Затем она вызывает процедуру "найти_распределение", кото-
которая вырабатывает пробный план и возвращает его через переменную
<< ОпПуть» и связанные с ней переменные «ЗакНакопители» и
«НакопПуть». Вычисляется значение индекса для «ЗакНакопители».
Затем зто значение сравнивается со значением индекса, содержащимся
в факте "оптимальный_план". Если индекс для «ЗнакНакопители»
будет более высоким, то текущий факт "оптимальный_план" будет за-
заменен на одноименный факт, содержащий текущие значения переменных
«ОпПуть» и «НакопПуть». Затем процедура "найти_оптимальное рас-
распределение" возвратится назад к процедуре "найти _ распределение" с тем,
чтобы получить еще один пробный план. Если значение индекса для нового
плана окажется более высоким, чем значение индекса, хранящееся в теку-
текущем факте "оптимальнь1Й_план", то этот факт будет заменен на новый,
содержащий новый план. (Обратите внимание на сходство описываемого
метода с одним из решений упражнения 4.1.) Данный процесс будет про-
продолжаться до тех пор, пока процедура "найти_распределение" не сгене-
сгенерирует все возможные варианты плана. После этого второе правило про-
процедуры "найти_оптимальное_распределение" возвратит план, содержа-
содержащийся в последнем добавленном в программу факте "оптимальный_план".
Процедура "распределить _операторов "
Процедура "найти _ распределение" вызывает процедуру "распре-
делить_операторов" с тем, чтобы отыскать распределение операторов
на один час рабочей смены. Алгоритм работы процедуры "распре-
делить_операторов" основан на нескольких эвристических предположе-
предположениях. Во-первых, каждый из присутствующих операторов должен быть
приставлен к какой-нибудь производственной установке в течение каждо-
каждого часа рабочей смены. Во-вторых, если в каком-либо накопителе имеются
изделия, подлежащие обработке, то по крайней мере один оператор должен
быть приставлен к установке, которая обрабатывает изделия, поступаю-
поступающие из этого накопителя. Две данные эвристики исключают из рассмотре-
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 359
ния многие бесполезные планы. Если мастер не хочет в течение нескольких
часов смены трогать заказы, собирающиеся вводном из промежуточных на-
накопителей, то он может выполнить одно из следующих действий:
1) удалить соответствующие факты "заказ" из базы данных и после
этого выработать план; или
2) скорректировать выработанный программой план и снять с нужной
установки всех операторов.
Процедура "найти_распределение" рекурсивно вызывает сама себя
по одному разу на каждый час рабочей смены. После вызова процедуры
"распределить_операторов" для отыскания распределения операторов
по установкам на один час, она вызывает процедуру "от накопит к на-
накопит", чтобы вычислить объем работы, который будет выполнен за этот
час при данном распределении операторов. (После этого процедура "най-
"найти _ распределение" может возвратиться назад к процедуре "распреде-
лить_операторов" с тем, чтобы найти иное распределение.) Как и про-
процедура "распределить_операторов", процедура "от_накопит_к_на-
копит" рекурсивно вызывает себя по одному разу на каждый накопи-
накопитель. Процедура "от_сост_к_сост" вызывает процедуру "от_зака-
за_к_ заказу", которая рекурсивно вызывает сама себя по одному разу
на каждый заказ, находящийся в накопителе. Процедура "от_зака-
за_к_заказу" всегда отдает приоритет в использовании установки перво-
первому заказу из полученного списка. Остальные заказы будут обрабатывать-
обрабатываться только после обработки первого.
Оценка алгоритма планирования
В приведенной здесь форме планирующая компонента программы
не способна найти оптимальный план для всех ситуаций, с которыми мо-
может столкнуться мастер. Она корректно работает только в тех производст-
производственных ситуациях, которые считаются нормальными. Однако для того,
чтобы можно было работать в экстраординарных ситуациях, программа
снабжена большим числом точек входа, обращаясь к которым мастер
сможет манипулировать критически важными ресурсами с тем, чтобы
повлиять на алгоритм планирования. Важной точкой входа, отсутствую-
отсутствующей в прототипе, является точка входа, которая обеспечила бы возмож-
возможность корректировки базы данных "заказ".
Чтение текста программы
Ниже приводится текст программы. Каждая компонента программы
помечена в соответствии с ее уровнем и категорией (интерфейс с пользо-
пользователем, вывод и т.д.). План программы, приведенный ранее, поможет
разобраться в ней.
360
ПРИЛОЖЕНИЯ
Соглашения об обозначениях
В программе содержится много процедур, названия которых заканчи-
заканчиваются цифрой "О". Это делается в соответствии с соглашением о том,
что такие процедуры вызываются другими процедурами с точно та-
таким же названиями, но без цифры "О" в конце. Например, процедура
"построить_список_накопитО" вызывается процедурой "построить спи-
сок_накопит". Назначение процедуры "построитьсписокнакопит" со-
состоит в том, что она подготавливает аргументы для процедуры "постро-
ить_список_накопитО"; именно процедура "построить_список_нако-
питО" и выполняет основную работу.
% Программа планирования работы завода
% Соглашения об именах переменных: . ж. ,» -,,ff, •
% Накоп Наименование накопителя, т.е. 1,2,3,4 или 5
% НакопА, НакопБ НакопБ — это накопитель, располагающийся
% следующим после накопителя НакопА
Это список, показывающий, какое
количество изделий каждого заказа распо-
располагается в каждом накопителе, т.е. список
вида: [ в (Накоп.Заказы),. . . ]
Начальный список накопителей
i Заключительный список накопителей (после
[ окончания обработки изделий)
Список, состоящий из списков накопителей,
по одному на каждый час
Список заказов вида: [ заказ (ИД,Количество),
% Накопители
% НачНакопители
% ЗакНакопители
%
% НакопПуть
% Заказы
% ЗаказыХ ' ' Список заказов в час X
% ЗаказыУ *, ,:!' Список заказов в час Y, где Y = X + 1 \.
% ЗаказыА ,^ Список заказов в накопителе А ' .
% ЗаказыБ т ' Заказы в накопителе Б (Б — это накопитель,
% расположенный вслед за накопителем А)
% ЗаказыХА 'Л'/' Список заказов в час X в накопителе А
% ИД Уникальный идентификатор заказа
% СписокОпер , Список количества операторов, приписанных к
% каждой установке, т.е. список вида:
% [оп(Установка, Количество),.. . ]
% ОпПуть -по;>л'.-. Список, элементами которого являются списки
% "СписокОпер", по одному на каждый час
Ш. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 361
% НачЧас Начальный час
% ЗакЧас Заключительный лас
% Индекс Относительная мера того, насколько много
% работы сделано к концу смены
% ОстПроизводительность Остаточная производительность уста-
% новки в единицу времени после того, как
% был выполнен некоторый объем работ
7о7о7о7о7о7о7о7с7о7с7о7о7,
ПРОЦЕДУРЫ ИНТЕРФЕЙСА С ПОЛЬЗОВАТЕЛЕМ
% СТАРТ (уровень 1; интерфейс с пользователем) ' •''
текущий _ час (8). . ,-т:
% + ¦• •. ,Н
старт (Час) : —
retract (текущий_час (_)), , .
assert (текущий _ час (Час) ),
nl, печ( ' (Час равен ', Час,')'),
%
вводполя (' Нужно ли вводить новое задание? (да или нет) ',
Ответ, нет, элемент (Ответ, [да, нет])),
(Ответ = да, добавить_работу (Час, _) ; Ответ =нег), !,
обработка смены (меню, план, Час, [ ], [ ] ).
% ОБРАБОТКА СМЕНЫ (уровень 2; интерфейс с пользователем)
%
% Процедура "обработка_смены" представляет собой самый высокий
% уровень интерфейса с пользователем — цикл опроса пользователя.
% Каждому элементу меню соответствует одно правило.
% Последней подцелью каждого правила является рекурсивный
% вызов данной процедуры.
конец_сменыA3). % час, когда заканчивается смена.
% Условие окончания:
% + + + + +
обработка_ смены (меню, _, Час, НакопПуть, ОпПуть) ;-*"»'
конец _ смены (Час),
печ( ' Конец смены в час ', Час,' . '),
построить список накопит (Час, ЗакНакопители), <г
nl, печ (' Состояние заказов: '),
выдатьпосл накопители ( [ЗакНакопители! ), ! .
362 ПРИЛОЖЕНИЯ
обработка_ смены (меню, Умалч_знач, Час, НакопПуть, ОпПуть) :-
nl, печ(' (Час равен ', Час,')'),
(Умалч_ знач = план,
печ(' (требуется новый план) ')
true
),
печ( ' команда? (план, обработка, помощь — для вывода
списка '),
вводполя (' возможных команд) ',
Ответ, Умалч знач,
( ОпПуть = [ ], % если список ОпПуть пуст:
( Ответ = план
печ(' Вы должны построить план! '),
fail '
) ¦ ' I
ОпПуть \ == [], % если список ОпПуть не пуст: i
( элемент (Ответ, [план, обработка, помощь,
' показать работу , ;'
' показать операторов', ;
' показать план ',' конец дня ' ])
печ(' Вы ошибочно ввели ', Ответ),
печ(' Правильные команды:'),
печ_элем(' ', [план,обработка,помощь,
' показать работу ',
' показать операторов ',
' показать план ',' конец дня ' ]),
fail
конец аргумента "Условие" процедуры > ¦'
"вводполя"
! , обработка_ смены (Ответ, обработка, Час, НакопПуть, ОпПуть).
обработка_ смены (план, Умалчзнач, Час, _, _) : —
план_смены (Час, НакопПуть, ОпПуть),
!, обработка_смены(меню,Умалч_знач,Час,НакопПуть,ОпПуть).
HI. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 363
обработка_ смены (обработка, Умалчзнач, Час,
[Накопители \ НакопПуть],
[СписокОпер ! ОпПуть] ) :.-¦
НовЧас is Час + 1,
retract (текущий _ час (Час) ),
assert (текущий час (НовЧас)) ,
% добавить факты "заказ/4" для нового часа:
обработка_ часа (НовЧас, Накопители),
! , обработка_смены (меню, Умалч_знач, НовЧас, НакопПуть,
ОпПуть).
обработкасмены (помощь, Умалч_знач, Час, НакопПуть, ОпПуть) : —
печ(' Возможные команды:'),
печ_элем('
[' план (составить план на оставшуюся часть смены) ',
' обработка (смоделировать работу за следующий час) ,
' помощь',
' показать работу (повторно вычислить и показать ',
текущее состояние заказов) ',
' показать операторов (текущее распределение операторов) ',
' показать план (план на оставшуюся часть смены) ',
' конец дня ']),
! , обработка _ смены (меню, Умалчзнач, Час, НакопПуть, ОпПуть).
обработка_ смены (' показать работу ', Умалчзнач, Час,
[Накопители ] НакопПуть],
[СписокОпер ] ОпПуть]) : —
% построить список "НовНакопители", чтобы заменить
% список "Накопители" для данного часа:
построить_ список _накопит (Час, ТНакопители),
макс_операторов (Час, МаксОпер),
от_накопит_к_накопит(МаксОпер, ТНакопители, СписокОпер,
НовНакопители),
%
печ(' Заказы на ', Час,' часов '),
write(' Накопитель '),
заголовок_списка_накопитD),
выдать_ список _накопит (ТНакопители),
вводполя(' Нужно ли вводить новое'задание? (да или нет) ',
Ответ, нет, элемент (Ответ, [да,нет] )),
% л
(Ответ = да, добавить_ работу (Час, РабФлаг) , .;.-;
; |>, - " .'.
Ответ = нет, РабФлаг = нет новой _ работы
ПРИЛОЖЕНИЯ
( РабФлаг = новая _ работа,
write(' Заказ был добавлен, так как существовал '),
write (' текущий план '), nl,
печ(' Строится новый план ...'),
обработка_ смены (план, Умалч_знач, Час, [],[])
>
РабФлаг = нет_новой работы,
обработка _ смены (меню, Умалч_знач, Час,
[НовНакопители | НакопПуть],
[СписокОпер | ОпПуть])
)•
обработка_ смены (' показать операторов ', Умалч_знач, Час,
НакопПуть, [СписокОпер | ОпПуть] ) :-
печ(' Операторы в', Час,' часов'),
выдать _ список _ операторов (СписокОпер),
write(' Добавить или удалить операторов? '),
вводполя(' (добавить, удалить, продолжить) ',
Ответ, продолжить,
элемент (Ответ, [добавить, удалить, продолжить] )),
( ( Ответ = добавить ; Ответ = удалить ),
КОРР—операторов (Час, Ответ)
Ответ = продолжить
).
!, обработка_ смены (меню, Умалч_знач, Час, НакопПуть,
[СписокОпер | ОпПуть]). . »
обработка _смены( 'показать план ', Умалч_^знач, Час, НакопПуть,
ОпПуть) :-
nl,
печ(' Текущее распределение операторов: '),
выдать_оп_путь(Час, ОпПуть), nl,
%
конец _ смены (Конец),
write(' приведет к нижеследующему состоянию '),
печ(' заказов ',' к ', Конец,' часам: '),
выдать_посл_накопители(НакопПуть), nl,
! , обработка_ смены (меню, Умалч_знач, Час, НакопПуть, ОпПуть).
%
% СПЛАНИРОВАТЬ СМЕНУ (уровень 3; интерфейс с пользователем)
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 365
% Построить план на оставшуюся часть смены, начиная с часа
% Час и кончая концом смены
% ' +
план_ смены (Час, НакопПуть, ОпПуть) : —
конец_ смены (ЗакЧас),
найти_оптимальное_распределение(Час, ЗакЧас, НачНакопители,
ННакопПуть, НОпПуть),
%
% Переменная НачНакопители содержит описание работы за час
% (перед началом обработки).
nl,
печ(' Нижеследующее распределение операторов: '),
выдать_оп_путь(Час, НОпПуть), nl,
%
печ(' приведет к нижеследующему состоянию заказов ',
к ', ЗакЧас, ' часам: ' ),
% вывести последний список накопителей, содержащийся в
% новой переменной НакопПуть:
выдать_ поел _ накопители (ННакопПуть), nl,
%
печ(' введите принять, если план подходит, или '),
вводполя (' корректировка, если план нужно изменить ',
Ответ, принять,
( элемент (Ответ, [принять,корректировка] )
печ(' неверный ответ '), fail)
),
( Ответ = принять,
НакопПуть = ННакопПуть,
ОпПуть = НОпПуть
Ответ = корректировка,
коррплана (Час, НачНакопители, ННакопПуть, НОпПуть,
НакопПуть, ОпПуть)
)¦
OL
/О
'"' % ОБРАБОТКА ЧАСА (уровень 3; интерфейс с пользователем)
% Добавить факты "заказ" с ненулевыми количествами изделий.
I % + +
• обработка_ часа (Час, [в (Накоп, Заказы) [Накопители]) : —
: обработка_ накопителя (Час, Накоп, Заказы),
| ! , обработка_часа(Час, Накопители).
366 ПРИЛОЖЕНИЯ
обработка_часа(_, [ ] ).
% + + +
обработка_ накопителя (Час, Накоп, [заказ (ИД, Количество) | Заказы])
( Количество \ = = О,
assert( заказ (Час, Накоп, ИД, Количество))
Количество = О
),
!, обработка_ накопители (Час, Накоп, Заказы).
обработка накопителя (_, _,[]).
%
% ДОБАВИТЬ РАБОТУ (уровень 3; интерфейс с пользователем)
% + - . ( '
добавить_ работу (Час, Флаг) : —
% проверить ИД по списку принятых заказов.
вводполя (' Введите наименование заказа или слово "конец" ',
ИД, конец, true),
( ИД = конец,
Флаг = нет _новой_ работы
ИД \ = = конец,
вводполя (' Количество изделий?',
НКоличество, 0, НКоличество > 0),
assert( заказ (Час, 1, ИД, НКоличество) ),
печ (' Заказ добавлен '),
Флаг = новая _ работа, ¦'¦'•' ".'.
добавить_работу(Час, _) ' '" *
% ПРОЦЕДУРЫ ПЛАНИРОВАНИЯ
%
% НАЙТИ ОПТИМАЛЬНОЕ РАСПРЕДЕЛЕНИЕ операторов смены.
% (уровень 4; планирование)
% + +
найти_оптимальное_распределение(НачЧас, ЗакЧас, _,_,_) :—
% построить начальный список накопителей, НачНакопители:
построить_список_накопит(НачЧас, НачНакопители),
assert (оптимальный _план (НачНакопители, 0, НачНакопители,
[НачНакопители], [ ]) ) ,
111. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 367
% поиск с возвратом по всем возможным распределениям на
% смену:
найти _ распределение (НачЧас, ЗакЧас, НачНакопители,
ЗакНакопители, НакопПуть, ОпПуть),
индекс__списка_ накопителей (ЗакНакопители, Индекс),
оптимальный_план(_, ОптимальныйИндекс, _,_,_),
( Индекс > ОптимальныйИндекс,
один_раз(геиас1(оптимальный_план(_,_,_,_,_) ) ),
assert (оптимальный _ план (ЗакНакопители, Индекс,
НачНакопители,
НакопПуть, ОпПуть) )
Индекс = < ОптимальныйИндекс
), fail.
найти_оптимальное_распределение(_, _, Накопители, НакопПуть,
ОпПуть) :- ;.
retract( оптимальный_план(_, _, Накопители,
НакопПуть, ОпПуть) ), ! .
% ПОСТРОИТЬ СПИСОК НАКОПИТЕЛЕЙ (уровень 5; планирование)
% Выяснить объем работы на каждом накопителе для часа Час:
% + -
построить_список_накопит(Час, Накопители) : —
findall(S, накопитель (S), S Список),
сп_неповт_знач(ИД0, заказ(_, _, ИДО, _) , СписокИД),
построить_список_накопитО(Час, СписокИД, БСписок, Накопители), !.
построить_список_накопитО(_, _,[],[]).
% + + +
построить_список_накопитО(Час, СписокИД>[8 | БСписок],
[ в (S, Заказы) J Накопители] ) : -
findall (заказ (ИД1, Количество),
(элемент (ИД1, СписокИД),
( заказ (Час, S, ИД1, Количество)
not( заказ (Час, S, ИД1, Количество) ),
Количество = 0 % 0 если отсутствуют факты "заказ"
)
), % конец второго аргумента предиката "findall"
Заказы),
! , построить_список_накопитО(Час, СписокИД, БСписок,
Накопители).
368 ПРИЛОЖЕНИЯ
% ИНДЕКС СПИСКА НАКОПИТЕЛЕЙ (уровень 5; планирование)
% Вычислить значение индекса для списка накопителей. Это значение
% характеризует объем выполненной работы. Для каждого
% накопителя умножить число, являющееся обозначением накопителя,
% на объем работы на этом накопителе.
индекс_списка_накопителей( [ ], 0).
% +
индекс_списка_накопителей( [в(Накоп, Заказы) | Накопители],
%
SИндекс) :—
индекс _ списка _ заказов (Заказы, ИндексЗ),
!, индекссписка накопителей (Накопители, БИндексО), ,*,,,
БИндекс is БИндексО + (Накоп * ИндексЗ). .;:
индекс_списка_заказов([ ], 0). -':
индекс _ спи ска _ заказов ( [заказ (_, Количество) | Заказы ], ИндексЗ) ¦
!, индекс_списка_заказов (Заказы, ИндексЗО),
ИндексЗ is ИндексЗО + Количество.
%
% НАЙТИ РАСПРЕДЕЛЕНИЕ (уровень 5; планирование)
%
% Это — базовый блок построения плана. Он вычисляет ОпПуть (т.е.
% распределение операторов на период от НачЧас до ЗакЧас) и
% НакопПуть (т.е. объем работы, который будет выполнен в резуль-
% тате данного распределения операторов). Процедура рекурсивно
% вызывает сама себя один раз на каждый час смены.
% Окончить, если достигнут заключительный час:
% + + +
найти _ распределение (ЗакЧас, ЗакЧас, ЗакНакопители, ЗакНакопители,
[[
найти_ распределение (НачЧас, % + начальный час
ЗакЧас, %+заключительный час
НакопителиХ, % + работа, выполненная за
% предыдущий час
ЗакНакопители, % -работав конце смены
[ НакопителиY | НакопПуть ], % —
[СписокОпер! ОпПуть ] % - ;л
) :-
НачЧас < ЗакЧас, : а -^.••<>:"-П
макс_операторов (НачЧас, МаксОпер),
lib ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 369
% поиск с возвратом по всем распределениям часа:
распределитьоператоров (НачЧас, МаксОпер, НакопителиХ,
СписокОпер"),
от_накопит_к_накопит (МаксОпер, НакопителиХ, СписокОпер,
Накопители Y),
НовЧас is НачЧас + 1,
найти_распределение(НовЧас, ЗакЧас, НакопителиУ,
ЗакНакопители, НакопПуть, ОпПуть).
/о
% РАСПРЕДЕЛИТЬ ОПЕРАТОРОВ (уровень 6; планирование)
%
% По заданному значению переменной "Накопители" (список того,
% как много работы собрано в каждом накопителе) выработать
% значение переменной "СписокОпер" (распределение операторов).
% Для каждого накопителя осуществляется рекурсивный вызов
% данной процедуры.
распределить_операторов(Час, % +
Опер, % +операторы, подлежащие
% распределению
[в(НакопА, ЗаказыА) \ Накопители],% спи-
( '¦'" % сок накопителей (+)
| ,_ . , [оп(Уст,Чис) (СписокОпер] % — распре-
¦-'"•; "¦"•>¦ % деления операторов
WZ ' ) -
f Опер > 0, % не пользоваться данным правилом, если О
% операторов
наименование_установки (Уст, НакопА, НакопБ),
( пусто (ЗаказыА), % оставшиеся заказы — нулевое коли-
% чество изделий
Г- Чис = 0,
i НовОпер is Опер
± ;
not ( пусто (ЗаказыА)),
производитуст (Уст, Опер, Чис, _), % сгенерировать значение
• f , % переменной "Чис".
%
W'% послать на установку, по крайней мере, одного оператора,
% если в накопителе НакопА есть работа:
Чис > 0, % не разрешается умалчиваемое значение произ-
% водительности, равное нулю
НовОпер is Опер — Чис
).
распределить операторов (Час, НовОпер, Накопители, СписокОпер).
370 ПРИЛОЖЕНИЯ
% Приписать к установке 0 операторов, е.сли не осталось свободных
% операторов (нулевое значение второго аргумента) или если список
% Заказы А пуст; В списке Накопители (третий аргумент) должно быть
% не менее двух элементов:
распределить_операторов(Час, Л % +
0, % +опер
[ в (НакопА, ЗаказыА), % +
в(НакопБ, ЗаказыБ) \ Накопители], ' \
[оп(Уст, 0) [СписокОпер] % - i
) ¦¦- .-ь
пусто (ЗаказыА), "
наименование_установки (Уст, НакопА, _),
распределить_операторов (Час, 0,
[ в (НакопБ,ЗаказыБ) ', Накопители], -
СписокОпер).
% Следует распределить всех операторов. Процедура "распределить_ ' _•
% операторов" потерпит неудачу и вернется назад, если значение
% переменной "Опер" (второй аргумент) не равно нулю для последней
% структуры "в (_,_)" в списке накопителей:
распределить_операторов(_,0, [в(_ , _)], [ ]).
% ПУСТОЙ СПИСОК ЗАКАЗОВ (используется в процедуре
% "распределить _операторов")
% Проверить то, что во всех структурах "заказ (_,_)" имеется
% нулевое количество изделий:
пусто([заказ(_,0) ! Заказы] ) :-
пусто (Заказы).
пусто([]).
(jf
70 ~
% ОТ НАКОПИТЕЛЯ К НАКОПИТЕЛЮ (уровень 6; планирование)
% По заданным значениям переменных НакопителиХ (положение
% заказов в час X) и СписокОпер (распределение операторов) вычислить
% значение переменной Накопители^ (положение заказов в час Y,
% гдеУ = Х+ 1).
% На каждый накопитель приходится один рекурсивный вызов данной
% процедуры.
% + + +
от_накопит_к_накопит (МаксОпер, НакопителиХ, СписокОпер,
%
НакопителиY) : —
% построить пустой список "ПрибывающаяРабота":
сп_неповт_знач(заказ(ИД, 0), заказ(_,_, ИД, _),
Прибывающая Работа),
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 371
от_накопит_к_накопитО(МаксОпер, Прибывающая Работа,
НакопителиХ, СписокОпер, Накопители Y).
% последний элемент "в(_, _)" в списке накопителей:
от_накопит_к_ накопитО (_, % +
ПрибывающаяРабота, % +
[в(_, ЗаказыХ)], % +
СписокОпер, % +
[в(_, Заказы Y)] % -
\ ._
от_заказа к_заказу@, ПрибывающаяРабота, ЗаказыХ, ЗакаэыУ), !.
от_накопит_к_някопитО (МаксОпер, % +
ПрибывающаяРабота, % +
[в (НакопА,ЗаказыХА), % + работа час X
в (НакопБ,ЗаказыХБ)| НакопителиХ],
СписокОпер, % +
[в (НакопА.ЗаказыУА), % - работа час У
в (НакопБ,ЗаказыУБ) ] НакопителиУ]
% найти значения переменных "Число_опер" и "Установка" для нако-
% пителей Аи Б в списке "СписокОпер":
найти_установку (СписокОпер, Установка, НакопА, НакопБ,
Число_опер),
производит_уст (Установка, МаксОпер, Число_опер,
Производительность),
от_заказа_„к_заказу (Производительность, ПрибывающаяРабота,
ЗаказыХА, ЗаказыУА,
СделаннаяРабота),
!,от_накопит_к_накопитО (МаксОпер,
СделаннаяРабота,
[в (НакопБ ,ЗаказыХБ )! НакопителиХ ],
СписокОпер,
[в (НакопБ.ЗаказыУБ)! НакопителиУ]) .
% ОТ ЗАКАЗА К ЗАКАЗУ (уровень 7; планирование)
с/(.
% По заданным значениям переменных "Производительность" (произ-
%водительность установки), "ЗаказыХ" (список работы последнего
% часа) и по списку прибывающей работы, поступающей в виде обра-
% ботанных за этот час изделий, выработать значение переменной
% "ЗаказыУ" (новый список работы на следующий час) .
% Осуществляется по одному рекурсивному вызову данной процедуры
% на каждый заказ.
372 ПРИЛОЖЕНИЯ
от_заказа_к_заказу (_, [ ], [ ], [ ], [ ]).
от_заказа_к_заказу (Производительность, % +
[заказ (Наименование,КоличествоПР) \ ПрибывающаяРабота ],
% + Прибывающая работа
[заказ (Наименование,КоличествоХ) | ЗаказыХ],
% + Заказы в час X
[заказ (Наименование,КоличествоУ) ] ЗаказыУ],
% - Заказы в час Y,
[заказ (Наименование,КоличествоСР)! СделаннаяРабота]
% - Сделанная работа »
) :- . ¦¦'*
Производительность > О,
фактически_сделано (КоличествоХ, Производительность,
КоличествоСР),
КоличествоУхз КоличествоХ — КоличествоСР + КоличествоПР,
ОстПроизводительность is Производительность — КоличествоСР,.
!, от_заказа_к__заказу (ОстПроизводительность,
ПрибывающаяРабота, ЗаказыХ, ЗаказыУ,
СделаннаяРабота).
от_заказа_к_заказу@, %+ Производительность
[заказ (Наименование,КоличествоПР) ', ПрибьшающаяРабота],
% + Прибывающая работа
[заказ (Наименование,КоличествоХ)! ЗаказыХ], %+ Заказы в
%часХ
[заказ (Наименование,КоличествоУ) | ЗаказыУ], % - Заказы в
% час У
[заказ (Наименование^) ! СделаннаяРабота] % Сделанная работа
):-
% добавить объем поступившей работы:
КоличествоУ is КоличествоХ + КоличествоПР,
% Сделанный объем работ равен нулю:
!,от_заказа_к_заказу@, ПрибывающаяРабота, ЗаказыХ,
ЗаказыУ, СделаннаяРабота).
%
% НАЙТИ УСТАНОВКУ (уровень 7; планирование)
%
% По заданному значению переменной "СписокОпер" (список распре-
% деления операторов) и по наименованиям двух накопителей, НакопА
% и НакопБ, выработать значения переменной Уст (наименование ус-
%тановки, которая обрабатывает изделия, поступающие с НакопА,
%и помещает их в НакопБ) и переменной Чис (число операторов на
% установке).
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 373
7с + - + +
найти_установку ([оп(Уст.Чис)! СписокОпер], Уст, НакопА, НакопБ,
Чис) :-
наименование—установки (Уст, НакопА, НакопБ),!.
найти_установку([_ ', СписокОпер], Уст, НакопА, НакопБ, Чис) :—
найти_установку (СписокОпер, Уст, НакопА, НакопБ, Чис),!.
7о ФАКТИЧЕСКИ СДЕЛАННАЯ РАБОТА (уровень 8; планирование)
% Если Объем работы меньше имеющейся Производительности,
% то Количество обработанных изделий равно Объему работы,
% в противном случае Количество обработанных изделий равно
% Производительности:
фактически__сделано (О, П, К)
фактически-сделано (О, П, К)
фактически_сделано (О, П, К)
О, К = О,!.
-О-П>0, К = П,1.
-О-П=< О, К = О, !.
% БАЗЫ ДАННЫХ И ИНТЕРФЕЙСЫ БАЗ ДАННЫХ
су0
% БАЗЫ ДАННЫХ "ПРОИЗВОДИТЕЛЬНОСТЬ УСТАНОВКИ"
% (уровень 7; планирование)
%
% Производительность установок в час; Переменная 'Число" обозна-
% чает число операторов.
% +Наим.+ ?
производит_уст (альфа, МаксОпер, Число, Производительность) :—
( % если переменная "Число" не конкретизирована, то
% сгенерировать ее значение:
var (Число), ген_чисел (МаксОпер, Число)
nonvar (Число), Число > О
),
% 5 изделий на оператора в час:
Производительность is Число * 5.
производит_уст(бета, МаксОпер, Число, Производительность) :—
( var (Число),
ген_чисел (МаксОпер, Число)
nonvar (Число), Число > О
374 ПРИЛОЖЕНИЯ
( Число = 1, Производительность = 15
Число = 2, Производительность = 20
Число > 2,
Производительность is 20+ ((Число - 2) * 2)
% если на установке работает более двух операторов, i
% то установка производит по два дополнительных изделия ;
% на каждого оператора сверх двух. f
)• -8
производит _уст (гамма, _, Число, Производительность) :—
% на установке "гамма" должны работать ровно два оператора:
( var (Число), Число = 2
nonvar (Число), Число >= 2 ' -
).
Производительность = 20.
производит_уст (дельта, МаксОпер, Число, Производительность) :—
( var (Число), ген_чисел (МаксОпер, Число)
nonvar (Число), Число > 0
),
% 8 изделий на оператора в час:
Производительность is Число * 8.
% умалчиваемое значение:
производит_уст(_,_, 0,0).
у0
% МАКСИМАЛЬНОЕ ЧИСЛО ОПЕРАТОРОВ
% (уровень 6; планирование)
% + -
макс_операторов (Час, Число) :—
% построить список операторов, все еще находящихся на работе
% в течение часа "Час":
findall (X, послать (Час, оператор (X)), Список),
length (Список, Число), !.
%
% БАЗА ДАННЫХ "ОПЕРАТОР" (уровень 7; планирование)
% Данные факты вводятся в программу интерфейсом с таймером.
% 8 = 8 часов утра (время прихода оператора на работу) .-:?
оператор (8, джек). . ., ¦. ,.,,... ,. *
оператор(8, марта). , ;.
I1L ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 375
оператор (8, сюзан).
оператор(8, барни).
оператор (8, фред).
% дуг приходит позже:
% оператор (9, дуг).
% барни и фред уходят с работы в 11.00:
% опровергнуть A1, оператор (8, барни) ).
% опровергнуть A1, оператор (8, фред)).
OL _
/у ,
% БАЗА ДАННЫХ "НАКОПИТЕЛЬ" (уровень 6; планирование)
% Накопитель - это место, где накапливаются изделия перед обработ-
% кой на установке и после обработки.
% 1 == совершенно не обработано;
% 5 == обработка закончена.
накопитель A). % начало,
накопитель B).
накопитель C).
накопитель D).
накопитель E). % конец.
а0
% БАЗА ДАННЫХ С НАИМЕНОВАНИЯМИ УСТАНОВОК
% (уровень 7; планирование)
% установка "альфа" обрабатывает детали, поступающие из накопителя
% 1 и помещает обработанные детали в накопитель 2:
наименование_установки (альфа, 1, 2).
наименование_установки (бета, 2, 3).
наименование_установки (гамма, 3, 4). ,
наименование—установки (дельта, 4, 5).
а _ i_
/о —
% БАЗА ДАННЫХ "ЗАКАЗ" (уровень 6; планирование)
% Каждый заказ, подлежащий обработке, представляется в программе
% в виде фактов нижеследующей формы:
% Час Накопитель ИД Изделий
заказ(8, 1, доу, 18).
заказ (8, 1, ' макгроу, 25).
%
% БАЗА ДАННЫХ С ИНФОРМАЦИЕЙ О ВРЕМЕНИ
%
% Данная база данных позволяет процедуре "послать" находить кор-
% ректное число операторов для заданного часа.
376 ПРИЛОЖЕНИЯ
порождение (9, 8).
порождение A0, 9).
порождение A1, 10).
порождение A2, 11).
порождение A3,12).
порождение A4, 13).
Уо7о7о7о7о7о7о7о7о7о7о7с7о7о7о7о7
% ПРОЦЕДУРЫ ВЫВОДА ИНФОРМАЦИИ
%
% ВЫДАТЬ ОП ПУТЬ (уровень 3; вывод)
% Вывести распределения операторов по часам рабочей смены.
выдать_оп_путь(_, []).
выдать_оп_путь(Час, [СписокОпер \ ОпПуть]) :—
length (СписокОпер, Чис), % Чис = число установок,
write (' Час '),
оп_нуть_заголовок (Чис).
выдать_оп_ путьО (Час, [СписокОпер \ ОпПуть]).
оп_путь_заголовок @) :— nl. % переход к новой строке.
оп_путь_заголовок (Длина) :—
Длина > 0,
write (' Уст. Оп. '),
Нов Длина is Длина - 1, :..
оп_путь_заголовок (НовДлина). ;,
выдать_оп_путьО (_, [ ]). <
выдать_оп_путьО (Час, [СписокОпер; ОпПуть]) :-
write (Час), write(' '), %табуляция
выдать_список_операторов (СписокОпер),
НовЧас is Час + 1,
выдать_оп_путьО (НовЧас, ОпПуть).
выдать_список_операторов ([]):— nl. % переход к новой строке.
выдать_список_операторов([оп(Установка,Опер)| СписокОпер]) : —
write (Установка), write (' '), % табуляция
write (Опер), write (' '), •'•
выдать_список_операторов (СписокОпер).
% ВЫДАТЬ ПОСЛЕДНИЙ СПИСОК НАКОПИТЕЛЕЙ
% (уровень 3; вывод)
%
% Перейти к последней переменной "Списки", а затем вызвать про-
% цедуру "выдать__список„накопит".
14. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР 377
выдать_посл_накопители ([Накопители ! НакопПуть]) :—
НакопПуть \ == [ ],
выдать__посл_накопители (НакопПуть).
выдать_посл_накопители ([Накопители]) :— % последний элемент
% списка "НакопПуть".
write (' Накопитель '),
заголовок_списка_накопит D),
выдать_список_накопит (Накопители).
заголовок_списка_накопит@) :— п1.
заголовок списка _ накопит (Длина) :—
Длина > О,
write (' Идентификатор Кол-во '),
НовДлина is Длина — 1,
заголовок_списка_накопит (НовДлина).
у0
% ВЫДАТЬ СПИСОК НАКОПИТЕЛЕЙ (уровень 4; вывод)
%
выдать_список_накопит ([ ]).
выдать_список_накопит([в(Накоп,Заказы)| Накопители]) :— .
write (Накоп), write (' '), % табуляция
выдать— список_заказов (Заказы), nl,
выдать_список_накопит (Накопители).
выдать_список_заказов ([ ]).
выдать_список_заказов ([заказ (ИД,Количество) J Заказы] ) :-
write (ИД), write (' '),
write (Количество), write (' '),
выдать_список_заказов (Заказы).
70
% ПРОЦЕДУРЫ КОРРЕКТИРОВКИ
%
% КОРРЕКТИРОВКА ОПЕРАТОРОВ (уровень 3; корректировка)
корр_операторов (Час, добавить) :—
write (' Введите имя оператора или слово "конец" '),
вводполя ( для продолжения работы ,
Ответ, конец, true),
( Ответ = конец
Ответ \ == конец,
assert ( оператор (Час, Ответ) ),
write (' Оператор добавлен '),
корр_операторов (Час, добавить)
378 ПРИЛОЖЕНИЯ
корр_операторов (Час, удалить) :—
write (' Введите имя удаляемого оператора или '),
вводполя (' слово "конец" ', Ответ, конец, true),
( Ответ = конец
Ответ \ == конец, >¦,
assert ( опровергнуть (Час, оператор (_, Ответ)) ), ,.
write (' Оператор удален '),
корр_операторов(Час, удалить)
)¦
а0
% КОРРЕКТИРОВКА ПЛАНА (уровень 4; корректировка)
корр_плана(Час, % +
НачНакопители, % + работа для часа "Час"
[НакопителиХ ! НакопПутьХ], %'+ текущ. НакопПуть
[СписокОперХ | ОпПутьХ], % + текущ. ОпПуть
[НакопителиУ; НакопПутьУ], %-откорр. НакопПуть
[СписокОперУ | ОпПутьУ] % — откорректир. ОпПуть
корр„списка_опер(Час, НачНакопители, НакопителиУ,
СписокОперХ, СписокОперУ),
НовЧас is Час + 1,
корр_плана(НовЧас, НакопителиУ, НакопПутьХ, ОпПутьХ,
НакопПутьУ, ОпПутьУ).
% значение переменной "НакопителиУ" вырабатывается процеду-
% рой, "корр_списка_опер" и является вторым аргументом
% при рекурсивном вызове
корр_плана (Час, НачНакопители, [ ], [ ], [ ], [ ]) :—
nl,
печ(' Планируемая работа завода к концу,смены: ' ),
write (' Накопитель '),
заголовок _списка_накопит D),
выдать_список_накопит(НачНакопители),!.
% КОРРЕКТИРОВКА СПИСКА ОПЕРАТОРОВ (уровень 5; корректировка)
% интерфейс с процедурой "корр_списка_оперО".
корр_списка_опер(Час, НачНакопители, НовНакопители, СписокОперХ,
СписокОперУ) :- '*
nl,
III. ПОКАЗАТЕЛЬНЫЙ ПРИМЕР ' 379
печ(' Планируемая работа завода на ', Час, ' часов: '),
write (' Накопитель '),
заголовок_списка_накопит D),
выдать_список_накопит (НачНакопители),
%
nl,
печ(' Текущее распределение операторов: '),
выдать_список_операторов (СписокОперХ),
nl,
%
макс_операгоров (Час, МаксОпер),
корр„списка_оперО (МаксОпер, СписокОпер, СписокОперУ),
%
% вычислить значение переменной "НовНакопигели" (резуль-
% таг нового распределения операторов):
от_накопит_к_накопит (МаксОпер, НачНакопители,
СписокОперУ, НовНакопители).
корр_списка_опер(_, _, [], [], []).
% КОРР_СПИСКА_ОПЕР0
% Корректировать все распределения операторов для заданного часа.
корр_списка_оперО (МаксОпер, % +
[оп (Уст,ЧисХ); СписокОперХ], % +
[оп(Уст,ЧисУ)[ СписокОперУ] %-
) ._
наименование-установки (Уст, НакопА, НакопБ),
печ(' Установка: ', Уст, ' между ', НакопА, ' и ',
НакопБ, ' '),
% проверить новое значение:
вводполя(' Количество операторов: ', ЧисУ, ЧисХ,
( ЧисУ > = 0, ЧисУ =< МаксОпер ) ),
!, корр_списка_оперО (МаксОпер, СписокОперХ,
СписокОперУ).
корр^списка_оперО(_, [],[]):-!¦
7o7o7n7o7o7o7o7o7o7o7o7o7cf'/o7o7c7o7o7o7o7o7o7o7o7o7o7o7
% ПРОЦЕДУРЫ ВВОДА-ВЫВОДА НИЗКОГО УРОВНЯ
% ПЕЧАТЬ
% Печать от одного до семи аргументов и перевод строки:
печ(А) :- write(A), nl,
печ(А, Б) :- write (A), write (Б), nl.
печ(А, Б, В) :- write(A), write(B), write(B), nl.
печ(А, Б, В, Г) :- write(A), write (Б), write(B), write (Г), nl.
380 ПРИЛОЖЕНИЯ
печ(А, Б, В, Г, Д) :- write(A), write (Б), write(B),
write (Г), write (Д) , nl.
печ (А, Б, В, Г, Д, Е) :- write(A), write (Б), write(B), write (Г),
write (Д), write(E), nl.
печ (А, Б, В, Г, Д, Е, Ж) :- write (A), write (Б), write (В), write (Г)',
write (Д), write (E), write (Ж), nl.
7о7с7с7о7о7с7с7о7о7с7о7о7с7с7о7о7о7с7с7о'
% РАЗЛИЧНЫЕ ПРОЦЕДУРЫ
%
% ПЕЧАТЬ ЭЛЕМЕНТОВ
печ^элем (Смещение, [А{ R]) :- ,
write (Смешение), write(A), nl,
печ „элем (Смещение, R).
печ__злем(_, []).
% ГЕНЕРАТОР ЧИСЕЛ
% Сгенерировать целое число N из диапазона от I до Макс, включая.
% границы диапазона:
ген_чисел(Макс, N) :-
ген_чиселО (Макс, 1, N).
ген_чиселО (Макс, Начало, Начало).
ген_чиселО (Макс, Начало, N) :—
НовНачало is Начало + 1,
НовНачало =< Макс,
ген_чиселО (Макс, НовНачало, N).
% СУММА СПИСКА ЧИСЕЛ
сумма ([ ], 0).
cyMMa([F| RJ, Итог) :-
сумма(R, Врем),
Итог is F + Врем.
% ЧИСТКА
чистка:- % избавиться от всех заказов, добавленных после
% 8 часов утра,
заказ (Час, А, Б, В),
Час>8,
retract (заказ (Час, А, Б, В) ), fail,
чистка :— % переустановить часы
retract (текущий_час (_) ),
assert (текущий_час (8) ).
% ИСПОЛЬЗУЕМЫЙ ФАЙЛ
:—consult(' послать '). % механизм наследования
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 381
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ
СиПролог .
Поставщик
Исходный текст транслятора СиПролог (CProlog), написанного на
языке Си, можно получить по адресу: Отдел архитектуры, Университет
Эдинбурга, Чамберс стрит, 20, Эдинбург, Великобритания, ЕН11JZ.
Эта версия легко переносится почти на любой 32-разрядный компью-
компьютер с операционной системой UNIX. Она была также перенесена на некото-
некоторые другие ЭВМ, в состав математического обеспечения которых входят
трансляторы с языка Си. СиПролог, однако, не будет работать на 16-раз-
16-разрядных машинах. Существует обширная библиотека программ, написан-
написанных на совместимом с СиПрологом диалекте языка Пролог (the SCORE
Prolog library). Эту библиотеку можно получить через Отдел информа-
информатики Стэнфордского университета и из других источников.
Синтаксис н встроенные предикаты
Синтаксис СиПролога совпадает с синтаксисом DEC-10 Пролога.
Встроенные предикаты СиПролога почти полностью идентичны встроен-
встроенным предикатам DEC-10 Пролога. Все программы, приведенные в данной
книге, будут работать в СиПрологе. При этом как-либо модифицировать
эти программы не потребуется.
Типы
Основными типами в СиПрологе являются атомы, целые числа, числа
с плавающей точкой и структуры. Если в качестве аргументов арифмети-
арифметического выражения выступают только целые числа, то результатом вычис-
вычисления этого выражения (к примеру, операции "is") будет также целое
число. Если в арифметическом выражении встречаются числа с плавающей
точкой, то результатом вычисления этого выражения будет число с пла-
плавающей точкой. Для выполнения деления существуют две разные опера-
операции. Результатом деления при помощи операции / всегда будет число с пла-
плавающей точкой, а результатом деления посредством операции // всегда
будет целое число. Числа с плавающей точкой можно записывать в экспо-
экспоненциальной форме, например: 6.1 ЕЮ.
Символы, располагающиеся между апострофами (т.е. одиночными
кавычками), например 'abc', образуют атом. Запись символов в промежут-
промежутке между двойными (т.е. обычными) кавычками является альтернативной
формой представления списка символов, который иногда называется стро-
строкой. Так, если интерпретатор встречает обозначение "abc", то он преоб-
преобразует его в [97, 98, 99].
382 ПРИЛОЖЕНИЯ
Директивы
Директивы — это команды интерпретатору, включенные в файл с тек-
текстом исходной Пролог-программы. Эти команды выполняются в момент
просмотра файла с исходным текстом. Директива начинается с симво-
символов :—, которые записываются, начиная с левого края поля. Если в файл
с исходным текстом включить директиву
:-write(' общий привет ')> nl.
то при просмотре файла эта директива вотедет в стандартный выходной
поток текст «общий привет» и символ начала новой строки. Обычно в
СиПрологе директивы используются для объявления операций и для о&
ращения к другим исходным файлам. Если в исходном файле с именем'
"a.pi" имеются следующие директивы: ' ' '^,
:-ор G00, xfy, ->). ,.>'.si:.-<J> '...*/
:-consult ('b.pl'). - .
то при просмотре файла "a.pl" сочетание символов —> будет обозначат)»
инфиксную операцию (см. разд. 3.10), и будет также просмотрен исход-:
ный файл "b.pl". *
Среда для разработки программ -
В СиПрологе отсутствует встроенный редактор, поэтому при разра-
разработке программ программист должен пользоваться средствами опера-
операционной системы UNIX. Обычно процесс разработки программы проте-
протекает следующим образом. Вначале программист при помощи текстового
редактора, скажем, редактора "vi", записывает программу. Затем про-
программист запускает интерпретатор СиПролога, который обрабатывает
файл с программой. Если обнаружится ошибка, то программист может
закончить сеанс работы с интерпретатором СиПролога, исправить про-
программу, находящуюся в файле, при помощи редактора и снова запустить
обработку файла с программой интерпретатором СиПролога. Все это, од-
однако, может оказаться неудобным при работе с программными файлами
большого размера, поскольку их обработка займет много времени.
В СиПрологе есть встроенный предикат "system/1", который позволяет
выполнять команды операционной системы непосредственно во время
работы с интерпретатором языка Пролог. Этот предикат позволяет испра-
исправить исходный файл с помощью системного редактора, не выходя из сеанса
работы с интерпретатором, например, при помощи команды:
I ?- system ("vi a.pl").
Заметьте, что команда операционной системы, являющаяся аргумен-
аргументом предиката "system", должна быть представлена в виде списка симво-
символов. В результате приведенного запроса начнется отдельный процесс редак-
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 383
тирования, который "заслонит" текущий процесс — сеанс работы с интер-
интерпретатором Пролога. После того как программист закончит редактирова-
редактирование файла и выйдет из редактора, управление вернется к процессу, с кото-
которым связана работа интерпретатора Пролога, и интерпретатор выведет:
да
Если файл "a.pl" уже был просмотрен интерпретатором до ввода при-
приведенного выше запроса "system", то становится необходимым повтор-
повторный просмотр этого файла при помощи запроса
| ?- reconsult ('a.pl').
При обычном двухкратном просмотре интерпретатором одного и того
же файла каждая фраза из этого файла будет дважды повторяться в теку-
текущей программе. Повторный просмотр файла при помощи запроса "re-
consult" позволяет избежать этого. При повторном просмотре файла по
запросу "reconsult" интерпретатор проверяет каждый предикат из файла
на наличие в текущей программе фраз, относящихся к этому предикату
(т.е. ищет в программе фразы, обладающие тем же именем и количест-
количеством аргументов, что и предикат из файла). Если такие фразы отыскива-
отыскиваются, то интерпретатор удаляет все эти фразы из программы и заменяет
их фразами из повторно просматриваемого файла. Таким образом, если
программист изменил в файле определение фразы, то в программе новое
определение займет место старого.
Для получения максимальной выгоды от использования средства
"reconsult" (т.е. для минимизации затрат времени на повторный просмотр)
рекомендуется организовывать программу в виде совокупности коротких
файлов, а не как один большой файл.
Ттладчик
Отладчик СиПролога может задавать поясняющие сообщения в четы-
четырех точках выполняемой процедуры;
1) когда анализируется лервая 4оаза процедуры (сообщение "Call",
т.е. "вызов");
2) когда процедура успешно выполнена (сообщение "Exit", т.е. "вы-
"выход") ;
3) когда система возвращается назад для рассмотрения второй или
следующей фразы процедуры (сообщение '"Back to" - "обратно к");
4) когда система достигает конца множества фраз, определяющих
процедуру (сообщение "Fail" - "неудача").
Для включения отладчика можно воспользоваться двумя методами.
Если ввести команду
! ?- trace.
384 ПРИЛОЖЕНИЯ
то отладчик станет выводить максимум отладочной информации при об-
обработке следующего запроса, т.е. будут печататься сообщения в четырех
точках каждой выполняемой процедуры. Если ввести команду
| ?— notrace.
то отладчик выключится.
Другой способ использования отладчика состоит в том, чтобы в од-
одну или несколько процедур ввести контрольные точки (spypoints). Тог-
Тогда отладчик будет автоматически включаться при вызове процедуры, в
которой есть контрольная точка. Например, команда
i ?— spy connects/3.
приведет к тому, что в процедуру "connects/З" будет введена контроль-
контрольная точка. Команда
i ?- nospy connects/3.
удалит эту контрольную точку. .
Пример сеанса работы
Приведем пример использования отладчика для наблюдения за выпол-
выполнением простой процедуры. Вопросительный знак в конце строки отла-
отладочной информации означает, что пользователь может вводить отладочную
команду. В данном примере пользователь нажимает клавишу возврата
каретки, а это означает, что отладчик должен продолжить печать отладоч-
отладочной информации с максимальным уровнем детализации.
полет (пиплз, ньюарк, релей) .
полет (пиплз, релей, нэшвилл).
! ?-trace.
да
! ?- полет (пиплз, X, Y).
A) О Call: полет (пиплз, _309, _324) 1 „и
A) 0 Exit: полет (пиплз,ньюарк,релей) ? д
X =ньюарк }ф
Y~ релей; ^
(/) О Back to: полет (пиплз, 309,_324) 1
A) 0 Exit: полет (пиплз, релей, нэшвилл) ? ^ ';,!,
X = релей %
Y= нэшвилл ; «'?. .-.у.:.,- -,v •¦','
A) 0 Back to: полет (пиплз, 309, 324) 1 •, i .
A) 0 Fail: полет (пиплз, _3'09, _324I „.,,,,„/. \
нет . -. .. . г.ч<.
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 385
В сообщениях, выдаваемых отладчиком, все переменные выводятся
со своими внутренними именами. Когда пользователь набирает символ ; ,
отказываясь от ответа, то запрос, активированный самым последним,
делается неудачным, а все переменные, конкретизированные при успехе
этого запроса, превращаются в неконкретизированные. Обратите внима-
внимание, что отладчик СиПролога отображает такие переменные в неконкрети-
зированном виде, когда печатает сообщение "Back to".
Расшифровка строки отладочной информации
Строка отладочной информации:
*A) 0 Call: полет (пиплз,_309,_3 24) ?
несет следующие сведения:
* означает, что в настоящее время в процедуре "полет/3" установле-
установлена контрольная точка.
A) — это уникальное обозначение конкретного вызова данной про-
процедуры.
0 показывает количество целей - прямых предков для данной кон-
конкретной подцели. Это, к примеру, позволяет судить о глубине, которой
достигла рекурсивная процедура.
Call: показывает, что это точка первоначального входа в процедуру.
полет (пиплз, 309, _324) — это сама подцель.
? — это сообщение-подсказка, означающее, что отладчик ждет ввода
отладочной команды.
После включения отладчика командой "trace" или при помощи конт-
контрольной точки в конце каждой строки отладочной информации будет
выдаваться данное сообщение-подсказка, свидетельствующее о возмож-
возможности ввода команды. Если в ответ пользователь нажмет клавишу возвра-
возврата каретки, то отладчик продолжит выдачу максимально подробной ин-
информации. Другие отладочные команды приведены ниже.
Отладочные команды
< возврат Отладчик будет печатать отладочные строки для всех про-
каретки> цедур (это — максимальный уровень детализации отла-
отладочной информации).
s (skip — пропустить). Отладчик ничего не будет печатать
до тех пор пока при данном вызове процедуры не встре-
встретятся отладочные сообщения "Exit" или "Fail".
1 (leap — перескочить). Отладчик ничего не будет печатать
до следующего вызова процедуры, в которой установ-
установлена контрольная точка.
n (nodebug — отключить отладку). Выключает отладчик
до того момента, пока система не выйдет на сообщение-
подсказку верхнего уровня.
13. Дж. Малпас
386 ПРИЛОЖЕНИЯ
a (abort — прекратить). Останавливает выполнение про-
программы и вызывает возврат к сообщению-подсказке
верхнего уровня.
Если нужно воспользоваться отладчиком для наблюдения только
за выполнением одной процедуры, то программист должен установить
контрольную точку в этой процедуре, запустить программу на счет и далее
вводить команду / (leap) в ответ на каждое сообщение-подсказку отладчи-
отладчика. Команда / предписывает отладчику ничего не печатать, вплоть до сле-
следующего вызова процедуры с контрольной точкой.
Команду s (skip) можно применять для пропуска отладочной инфор-
информации вплоть до выхода из процедуры или ее неудачи. Предположим,
что в точке вызова тщательно отлаживаемой процедуры (такой как "эле-
"элемент") отладчик печатает сообщение. Если воспользоваться командой s,
то все излишние подробности того, как процедура "элемент" достигает
успеха или неудачи, не будут показаны.
Компилятор
Для СиПролога нет компилятора.
Запомненные состояния
Просмотр файла исходных текстов с Пролог-программой требует
определенных затрат времени. Можно избежать этих затрат, если просмот-
просмотреть программу интерпретатором лишь один раз, а затем воспользоваться
командой "save", которая запишет в двоичный файл всю информацию о
текущем состоянии Пролог-системы, включая все фразы текущей програм-
программы. При вызове СиПролога из среды операционной системы задаваемый
аргумент воспринимается как имя файла с запомненным состоянием.
В нижеследующем примере пользователь задает просмотр файла интерпре-
интерпретатором, создает файл с запомненным состоянием, а затем выходит из
Пролога:
1 ?- consult('a. рГ).
да
! ?- save ('a. save').
да
I ?- halt. % конец сеанса.
Для того чтобы опять запустить СиПролог и восстановить запомненное
состояние, пользователь должен вызвать СиПролог из среды операционной
системы, указав в качестве аргумента имя файла с запомненным состоя-
состоянием:
$ cprolog a. save
Для больших программ восстановление запомненного состояния обычно
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 387
выполняется гораздо быстрее, чем просмотр интерпретатором исходного
файла. Однако файлы с запомненными состояниями, как правило, имеют
большой размер.
Интересным свойством запомненных состояний является то, что любые
невыполненные во время сеанса работы запросы также запоминаются и
выполняются, как только будет произведено восстановление. В ниже-
нижеследующем примере пользователь указывает, что после восстановления
запомненного состояния требуется выполнить запрос к процедуре "start":
| ?-save('a.pl'), start(8).
да
Таким образом, можно воспользоваться запомненными состояниями
для создания "выполнимой" версии Пролог-программы, в которой само
существование интерпретатора Пролога будет полностью скрыто от поль-
пользователя программы.
Интерфейс с иными языками программирования
В СиПролог можно добавить дополнительные встроенные предикаты,
если соответствующим образом модифицировать текст Си-программы,
реализующей интерпретатор, и перекомпилировать ее.
Расширения языка
В СиПрологе имеется расширение, предназначенное для написания
процедур нисходящего грамматического разбора с использованием форма-
формализма Грамматики определенных предложений (DCG). Посмотрите, как
в системе записи DCG будет выглядеть простая грамматика из гл. 6:
% Грамматика из гл. 6, представленная на Прологе :
% нетерминалы:
% Вход Выход Имя
объект (I, О, предложение) :— ,
объект (I, R, группа_существительного),
объект (R, О, глагольнаягруппа).
объект (I, О, группа_существительного): -
объект (I, R, артикль),
объект (R, О, существительное),
объект (I, О, глагольная_группа) : —
объект (I, R, глагол),
объект (R, О, группасуществительного).
% терминалы:
% Вход Выход Имя
объект([the ; R], R, артикль).
объект ([cow | R], R, существительное).
13*
388 ПРИЛОЖЕНИЯ
объект ([tail ! R], R, существительное).
объект ([shakes I R], R, глагол).
объект ([walks I R], R, глагол).
% Грамматика в форме записи DCG:
предложение —> группасуществительного, глагольнаягруппа.
группа_существительного —> артикль, существительное,
глагол ьная_ группа > глагол, группасуществительного.
артикль —> [the].
существительное —> [cow],
существительное —> [tail].
глагол —> [shakes].
глагол —> [walks].
Форма записи DCG обладает многими свойствами, облегчающими
написание грамматик. Подробное описание см. в [ПО].
Квинтус Пролог ¦ • .
Поставщик
Квинтус Пролог (Quintus Prolog) поставляется фирмой Квинтус
Компьютер Системз Инк. Он предназначен для ЭВМ, работающих под
управлением операционных систем UNIX и VMS. Вместе с транслятором
предоставляется большая библиотека вспомогательных программ. Квин-
Квинтус Пролог отличается очень высокой скоростью выполнения программ.
Синтаксис и встроенные предикаты
Синтаксис Квинтус Пролога такой же, как и у DEC-10 Пролога. Все
программы, приведенные в настоящей книге, будут (без необходимости
внесения в них каких-либо исправлений) работоспособны в среде Квин-
Квинтус Пролога. В Квинтус Прологе имеется большинство встроенных пре-
предикатов DEC-10 Пролога, а также ряд новых предикатов. Отличия во
встроенных предикатах между этими версиями Пролога в основном сво-
сводятся к различному управлению файлами.
Помимо встроенных предикатов "see", "tell" и т.д., описанных в
разд. 4.5, в Квинтус Прологе есть нижеследующие предикаты, в которых для
слежения за открытыми файлами применяются идентификаторы потоков.
open (F, M, S) F — это имя файла, М - один из трех атомов, обозна-
обозначающих режим работы с файлами — «read» (читать), «write»
(писать) или «append» (писать в конец файла). Этот предикат
открывает файл заданного вида и конкретизирует переменную 5,
которая становится уникальным идентификатором потока.
set_input(S) 5 должно быть уникальным идентификатором потока,
порожденным при вызое предиката "ореп/3" с аргументом, ука-
указывающим режим работы с файлом, равным read. Данный встроен-
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 389
ный предикат связывает файл, обозначенный переменной 5, с те-
текущим входным потоком.
set_output(S) S должно быть уникальным идентификатором потока,
порожденным при вызове предиката "ореп/3" с аргументом, ука-
указывающим режим работы с файлом, равным write или append.
Данный встроенный предикат связывает файл, обозначенный
переменной S, с текущим выходным потоком.
close (S) 5 должно быть уникальным идентификатором потока, порож-
порожденным при вызове встроенного предиката "ореп/3". Этот преди-
предикат закрывает файл, обозначенный переменной 51.
Пример :
,' ?- open('ap. data', read, SI),
set_input(Sl), ;
repeat,
read(R)
обработать (R),
R = end_of_file,
close (SI),
set_input(user).
Стоит отметить, что если встроенный предикат "set input" применяет-
применяется внутри запроса для переадресации входного потока к открытому файлу,
то после окончания выполнения запроса входной ноток автоматически
вернется обратно к терминалу. В СиПрологе описанное действие не осу-
осуществляется, если пользователь в запросе открывает файл при помощи
встроенного предиката "see". Если пользователь не закроет входной файл
в том же самом запросе при помощи предиката "seen", то интерпретатор
продолжит прием входных данных из открытого файла, а после достиже-
достижения конца файла сеанс работы с Прологом будет завершен.
Встроенный предикат "current_stream/3" можно использовать для
получения идентификаторов потоков и режимов работы любых открытых
файлов. Имеются разновидности и других предикатов ввода-вывода
("write", "read" и т.д.), в которых одним из аргументов служит иденти-
идентификатор потока и которые осуществляют чтение или запись в файл, связан-
связанный с этим идентификатором.
В Квинтус Прологе есть предикат форматного вывода "format/2",
форматизирующий тексты аналогично функции "printf" языка Си.
Команда "consult" в Квинтус Прологе означает то же самое, что и
команда "reconsult" в СиПрологе, т.е. для каждого предиката из просмат-
просматриваемого файла система удалит из текущей программы все фразы, отно-
относящиеся к этому предикату, а только потом добавит в программу из файла
данную фразу. Этот механизм осуществляет защиту от многократного
390 ПРИЛОЖЕНИЯ
добавления в программу одних и тех же фраз. Если объявить процедуру
как "многофайловую" ("multifile"), то данный механизм работать не
будет.
Типы
Основными типами в Квинтус Прологе являются атомы, целые числа,
числа с плавающей точкой и структуры. Как и в СиПрологе, если все ар-
аргументы арифметического выражения являются целыми, то результат
вычисления этого выражения (например, при помощи встроенного преди-
предиката "is") также будет целым. Если в выражении встречаются числа с
плавающей точкой, то в результате вычисления этого выражения получит-
получится число с плавающей точкой. Для выполнения деления, однако, есть две
разных операции. Результатом деления при помощи операции / всегда
будет число с плавающей точкой, а результатом деления посредством
операции // всегда будет целое число. Числа с плавающей точкой можно
записывать с указанием их порядка, например 6'.IE 10.
Как и в СиПрологе, запись символов между двойными кавычками
служит альтернативной формой записи списка символов.
Директивы
Если во время выполнения процедуры требуется добавлять и удалять
фразы определенного предиката, то этот предикат следует определить
как динамический при помощи директивы вида:
:— dynamic король/2.
Если предикат "король/2" не объявить как динамический, то при
употреблении по отношению к нему встроенных предикатов "assert" и
"retract" интерпретатор потерпит неудачу и выдаст сообщение об ошибке.
Встроенный предикат "clause" (см. разд. 4.9) также будет работать только
с динамическими предикатами.
Среда разработки программ
Квинтус Пролог можно запускать либо как самостоятельный процесс,
либо через специальный интерфейс с редактором EMACS. Если Квин-
Квинтус Пролог работает совместно с EMACS, то на экране дисплея, как пра-
правило, будут два окна. Верхнее окно содержит текст из исходного файла с
Пролог-программой, а нижнее окно — информацию Пролог-процесса, при-
причем обмен данными происходит через буфер редактора EMACS. Для окна
с файлом исходной программы имеются команды редактора EMACS,
обеспечивающие пошаговый просмотр или компиляцию фраз в активный
Пролог-процесс. К примеру, если все фразы некоторой процедуры сгруппи-
сгруппированы в одной части исходного файла, то с помощью одной EMACS-коман-
ды можно будет найти все эти фразы и просмотреть или откомпилировать
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 391
их. В редактор EMACS были внесены и другие расширения, обеспечиваю-
обеспечивающие работу с синтаксическими формами Пролога.
В окне обработки Пролога вся выходная информация Пролог-системы
автоматически заносится в буфер редактора EMACS. По окончании сеанса
работы этот буфер обычно теряется, хотя при помощи явного указания
можно переписать его содержимое в файл. Буфер - это своего рода
регистрационный механизм, хранящий сведения о сеансе работы. Сущест-
Существует EMACS-команда, позволяющая отыскать и повторно выполнить
запрос, введенный ранее в процессе работы.
Если в СиПрологе интерпретатор встречает запрос к предикату, не
содержащемуся в текущей программе, то он просто терпит неудачу. В Квин-
тус Прологе программист может определять поведение системы для случая,
когда попадется неизвестный предикат. По умолчанию запрос к неизвест-
неизвестному предикату вызывает включение отладчика. При помощи команд
отладчика программист может просмотреть или откомпилировать файл,
содержащий этот предикат (или ввести его с клавиатуры), и дать указание
системе повторить выполнение запроса.
Отладчик
Отладчик Квинтус Пролога в целом аналогичен отладчику СиПролога,
но обладает значительно большим количеством отладочных команд.
Компилятор
В Квинтус Прологе есть и пошаговый компилятор, и интерпретатор.
Во время одного сеанса можно свободно смешивать интерпретируемый и
откомпилированный коды. Компилятор является пошаговым в том смыс-
смысле, что в любом месте можно транслировать новые фразы в выполняющий-
выполняющийся Пролог-процесс. Откомпилированный код выполняется значительно
быстрее, чем интерпретируемый, но для интерпретируемого кода обеспе-
обеспечивается выдача большего объема отладочной информации. Как правило,
процедуру при разработке следует подвергать интерпретации, а затем,
после тщательной отладки, ее нужно компилировать.
Запомненные состояния
Механизм запомненных состояний Квинтус Пролога во многом по-
похож на этот механизм в СиПрологе. В версиях для операционной системы
UNIX можно запускать Пролог-процесс и восстанавливать запомненное
состояние просто при помощи ввода имени запомненного состояния в
командной строке операционной системы.
Интерфейс с иными языками программирования
Процедуры, написанные на других языках программирования, можно
постепенно подсоединять к Пролог-процессу и вызывать во время сеанса
работы, так же как и прочие встроенные предикаты. Имеются средства
392 ПРИЛОЖЕНИЯ
сопряжения с языками Си, Паскаль, ассемблер, Фортран, Кобол и Лисп.
Для каждого из этих языков существуют механизмы отображения их
структур данных на структуры данных Пролога и обратно с целью пере-
передачи аргументов.
Расширения
В Квинтус Пролог включено DCG-расширение, о котором рассказыва-
рассказывалось выше при описании СиПролога.
Разное
Фразы при просмотре или компиляции анализируются, подсистемой
проверки стиля программирования. Эта подсистема выдает предупреж-
предупреждающие сообщения о возможных ошибках (к примеру, о переменной,
которая встречается во фразе лишь один раз). Этот вид сообщений помо-
поможет локализовать ошибки правописания.
Индексация первого аргумента
В откомпилированных процедурах Квинтус Пролога (за исключе-
исключением динамических процедур) автоматически индексируется первый
аргумент. Это означает, что при выполнении запроса к процедуре для
ускорения доступа к фразам процедуры, имеющим такой же первый ар-
аргумент, как и у запроса, применяется хеш-таблица. Если первым аргу-
аргументом служит структура, то фразы индексируются по имени этой струк-
структуры.
Оптимизация остаточной рекурсии
В Квинтус Прологе автоматически осуществляется оптимизация оста-
остаточной рекурсии для процедуры, которая детерминированна в точке вызо-
вызова рекурсивной подцели. Оптимизация остаточной рекурсии — это метод
экономии стековой памяти, требующейся для выполнения запроса к про-
процедуре. Он обеспечивает то, что для обработки рекурсивной подцели про-
процедуры больше не выделяется дополнительных блоков стековой памяти.
Вместо этого рекурсивная подцель использует повторно те блоки стека,
которые были выделены для породившей ее цели. Поэтому процедура
может осуществлять рекурсию на любую глубину, пользуясь постоянным
числом блоков стековой памяти.
В качестве примера того, как можно воспользоваться преимущества-
преимуществами, предоставляемыми оптимизацией остаточной рекурсии, рассмотрим
две версии процедуры "суммировать". Эта процедура должна складывать
друг с другом все числа из списка.
% + -
суммировать!([], 0).
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 393
суммировать1([Ы | R], Итог):-
суммировать1 (R, Текущ_сумма),
Итог is N + Текущ_сумма.
% + +
суммировать2([ ], Итог, Итог).
суммировать2([М ( R], Текущ сумма, Итог): —
НовТекущ_сумма is N + Текущсумма,
суммировать2(Я, НовТекущсумма, Итог).
| ?- суммировать1([2, 2],Т1).
77=4
! ?- суммировать2([2, 2], О, Т2).
Т2 = 4
Компилятор не применит оптимизацию остаточной рекурсии к про-
процедуре "суммировать I", гак как в момент вызова рекурсивной подцели
(« суммировать 1(R, Текущсумма »)) остается еще одна подцель, кото-
которая должна быть выполнена. Компилятор употребит, однако, оптимиза-
оптимизацию остаточной рекурсии в случае процедуры "суммировать2", посколь-
поскольку к моменту вызова рекурсивной подцели («суммировать2(Р, Нов-
Текущсумма, Итог»)) все предыдущие подцели («НовТекущсумма
is N + Текущсумма») являются детерминированными, а после рекурсив-
рекурсивной подцели не располагаются никакие другие подцели.
Система программирования на Прологе фирмы Сайлоджик
Поставщик
Система программирования на Прологе фирмы Сайлоджик (Silogic
Knowledge Workbench, сокращенно — SKW) поставляется фирмой Сай-
Сайлоджик, Инк. Система SKW функционирует на многих компьютерах, рабо-
работающих под управлением операционной системы UNIX. Система SKW ос-
основана на СиПрологе, но обладает по сравнению с ним многими дополни-
дополнительными возможностями и расширениями.
Синтаксис и встроенные предикаты
Синтаксис SKW совместим с синтаксисом DEC-10 Пролога. Все про-
программы, приведенные в данной книге, будут работать в SKW, при этом не
потребуется вносить в них какие-либо исправления. В SKW имеется боль-
большинство встроенных предикатов DEC-I0 Пролога, а также большое коли-
количество новых предикатов. Наибольшие добавления в SKW связаны с
UNIX-подобным управлением файлами и с системными вызовами опера-
операционной системы UNIX.
394 ПРИЛОЖЕНИЯ
При работе с открытыми файлами в нижеследующих предикатах упот-
употребляются идентификаторы потоков.
fopen(F; M, S) F — имя файла, М - один из трех атомов, задающих
режим работы с файлом: г (read - чтение), w (write - запись) и
a (append - запись в конец файла). Этот предикат открывает файл
заданным образом и конкретизирует переменную S, присваивая
ей уникальный идентификатор потока.
gets(S, L) S — идентификатор потока, связанный с файлом, который
был открыт для чтения. L — список символов. Данный предикат
конкретизирует L следующей входной строкой из файла, ассоции-
ассоциируемого с S.
puts(S, L) Л - идентификатор потока, связанный с файлом, который
был открыт для записи в начало файла или в конец файла. L — спи-
список символов. Данный предикат помещает символы из списка L
в файл, ассоциируемый с S.
fclose(S) этот предикат закрывает файл, ассоциируемый с инденти-
фикатором потока S.
Пример :
! ?- fopen("ap. data", г, SI),
fopenf'ap. report", w, SO),
gets(SI, X),
обработка (X, Y),
puts(SO, Y),
puts(SO, "конец отчета"),
fclose (SI),
fclose(SO).
Предикат "namestream/2" дает имена и индентификаторы потока для
всех открытых потоков.
В SKW есть нижеследующие встроенные предикаты, обеспечивающие;
интерфейс с системными вызовами UNIX: J
chdir
chmod *
chown
fork
getpid
getenv
kill
nice
и т.д.
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 395
В SKW имеются следующие встроенные предикаты: "argc", который
дает количество аргументов командной строки при вызове Пролога из
операционной системы, и "argv", который вырабатывает список аргу-
аргументов командной строки. Существует также предикат форматного вывода
"writef/2", в котором можно задавать коды формата, сходные с обозна-
обозначениями формата в операторе "printf" языка Си.
Арифметические "вычислители" ("is", "<" и т.д.) позволяют в
дополнение к обычным арифметическим операциям вычислять еще ряд
функций:
sqrt(X) % квадратный корень из X
ехр (X) % число е в степени X
log (X) % натуральный логарифм X
loglO(X) % десятичный логарифм X
sin (X)
cos (X)
tan (X)
asin (X)
ас os (X)
atan(X)
и т.д.
Типы
Основными типами в SKW являются атомы, целые числа, числа с пла-
плавающей точкой и структуры. Как и в СиПрологе, если все аргументы
арифметического выражения — целые, то и в результате вычисления этого
выражения получится целое число. Если в арифметическом выражении
попадаются числа с плавающей точкой, то в результате вычисления этого
выражения получится число с плавающей точкой. В результате операции
деления / получается число с плавающей точкой, а в результате операции
деления // — целое число.
Как и в СиПрологе, альтернативной формой записи списка символов
служит строка символов, заключенная в двойные кавычки.
Существует альтернативная форма записи и для значений из ascii—ко-
ascii—кодовой таблицы. При этом перед символом записываются символы 0 и .
Будут эквивалентными такие списки:
[97,98,99] [О'а,О'Ь,О'с]
Для целей оптимизации, осуществляемой во время компиляции, в
SKW имеются нижеследующие объявления типов в директивах "mode"
(см. ниже подраздел "Директивы") :
compound Данный аргумент является составным термом,
list (X) Данный аргумент является списком; если X — имя типа,
то данный аргумент является списком термов этого типа.
396 ПРИЛОЖЕНИЯ
atomic Данный аргумент является атомом или числом,
atom Данный аргумент является атомом.
number Данный аргумент является целым Числом или числом с
плавающей точкой.
integer Данный аргумент является целым числом.
При помощи директивы "type" программист может определять допол-
дополнительные типы.
Директивы
В SKW различаются предикаты программы и предикаты данных. Фра-
Фразы предикатов программы нельзя добавлять и удалять. Все фразы, за-
загруженные при помощи встроенного предиката "load", по умолчанию
являются предикатами программы. Если фразы предиката должны из-
изменяться динамически, то этот предикат следует объявить как "data"
(данные). К примеру, нижеследующая директива превратит предикат
"текущаясумма/Г'в предикат данных:
: —data текущая сумма/1.
Для обеспечения оптимизации во время компиляции можно при по-
помощи директивы "mode" объявить для аргументов предиката направлен-
направленность (входной или выходной аргумент) и тип. С помощью директивы
"mode" можно также объявить предикат как детерминированный. На-
Например, в приводимом ниже правиле "итог" первый аргумент всегда дол-
должен быть составным термом, а второй (выходной) аргумент — целым
числом:
% +
итог (клиент (_, Тариф, Дни), Сумма) :—
Сумма is Тариф * Дни.
Следующая директива "mode" сообщает компилятору о роде аргументов
предиката "итог":
:—mode итог(+compound, —integer).
Если предикат "итог" должен быть детерминированным (т.е. быть успеш-
успешным только один раз), то можно информировать об этом компилятор,
поставив в директиве "mode" перед именем предиката знак плюс:
:— mode +итог( +compound,—integer).
Директива "mode", описывающая предикат, должна находиться в том же
исходном файле, где определяется этот предикат. Она не повлияет на ис-
исходный файл, если файл будет просматриваться интерпретатором, а не
компилироваться.
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 397
Существует и ряд других директив, информирующих компилятор
о свойствах предиката. Эта информация ^используется при оптимизации
программы. "Незаписывающий" ("writeless") предикат не содержит
обращений к предикатам "assert" и "retract". В "неупорядоченном"
("orderless") предикате не имеет значения порядок следования фраз.
Все аргументы предиката, обладающие свойством "без режима" ("mode-
("modeless") , являются двунаправленными. Во фразах "Несокращенного" ("cut-
less") предиката отсутствуют предикаты "сократить". Фразы предиката
"без ввода-вывода" ("ioless") не содержат предикатов ввода-вывода.
Среда разработки программ
Встроенный предикат "load'' ("загрузить") аналогичен предикату
"consult" ("просмотреть"). Отличие состоит в том, что предикат "load"
может загружать как объектные (т.е. откомпилированные), так и исход-
исходные файлы, и откажется загружать фразы, принадлежащие к уже загружен-
загруженной процедуре. Предикат "reload" ("повторно загрузить") аналогичен
предикату "reconsult" ("повторно просмотреть") : для каждой процедуры
из файла он отыскивает в текущей программе и удаляет фразы этой про-
процедуры, а затем переносит эту процедуру из файла в программу.
Систему SKW можно запускать как самостоятельный процесс. В этом
случае цикл разработки программ будет очень похож на цикл разработки
в СиПрологе. Предположим, что программист загрузил исходный файл
"а.рГ, а затем обнаружил в нем ошибку. Тогда он может воспользоваться
нижеследующим составным запросом, чтобы запустить текстовый редак-
редактор "поверх" Пролог-процесса, а после окончания сеанса редактирования
перезагрузить исправленный файл:
| ?-shell("via.pl"), reload('а.рГ).
Систему SKW можно также запустить как подпроцесс под управле-
управлением редактора EMACS. В этом случае вся выходная информация, полу-
полученная во время сеанса работы с Прологом, заносится в буфер EMACS.
Редактор EMACS был доработан, чтобы обеспечивать возможность про-
проведения сеансов работы с Прологом.
Система SKW предоставляет программисту возможность определять
ее поведение в случае, когда она встретит неизвестный предикат. По умол-
умолчанию при запросе к неизвестному предикату будет включен отладчик.
Отладчик
Отладчик SKW в основном сходен с отладчиком СиПролога. Однако
для того, чтобы проследить за выполнением запроса, этот запрос нужно
задать в виде аргумента встроенного предиката "trace/1". К примеру,
нижеследующий вызов дает возможность проследить за выполнением
398 ПРИЛОЖЕНИЯ
запроса к процедуре "служащий/3":
] ?- trace (служащий (X, Y, Z) ) .
Помимо сообщений "Call", "Exit", "Back to" и "Fail", отладчик при
выполнении запроса может печатать сообщения в трех дополнительных
точках:
5) перед тем, как предпринимается попытка унификации активного
запроса с заголовком фразы ("Head" — "Заголовок") ;
6) в точке, где унификация активного запроса и заголовка фразы
потерпела неудачу ("Miss" — "Мимо") ;
7) после успешной унификации активного запроса и заголовка фразы
в точке, обозначаемой "Neck" ("Шея").
Эти дополнительные сообщения позволяют увидеть результаты выпол-
выполнения унификации запроса с заголовком фразы. В SKW имеется гораздо
больше отладочных команд, чем в СиПрологе.
Компилятор
В SKW имеется внешний компилятор, который работает аналогично
компилятору языка Си. Принято, что имена исходных файлов Пролога
снабжаются расширением «.pi», а имена объектных (откомпилирован-
(откомпилированных) файлов — расширением «.ро». Компилятор вызывается командой
операционной системы «рЬс». Аргументами этой команды служат имена
исходных файлов, а на выходе компилятора создаются объектные файлы.
Объектные файлы можно постепенно загрузить в выполняющийся Пролог-
процесс при помощи встроенного предиката "load". Откомпилированные
процедуры нельзя отлаживать в диалоговом режиме.
Запомненные состояния
Работа с запомненными состояниями во многом аналогична СиПроло-
гу. Однако невыполненные запросы не включаются в запомненное состоя-
состояние. Для автоматического запуска программы после восстановления запом-
запомненного состояния программист должен определить программу с именем
"main/1". Если такая программа определена, то после восстановления
запомненного состояния будет выполнен следующий составной запрос:
I ?-argv(L), main(L), !.
Здесь «argv (L)»— это обращение к аргументам Пролог-процесса,
заданным в командной строке. Если пользователь прервет выполнение
Пролог-процесса, то оно возобновится с этого составного запроса, а Про-
Пролог не вернется к сообщению-подсказке верхнего уровня. Если програм-
программа "main/1" не определена, то после восстановления запомненного состоя-
состояния Пролог выйдет на сообщение-подсказку верхнего уровня. Можно
запустить Пролог-процесс и восстановить запомненное состояние, если прос-
просто ввести имя этого состояния в командной строке операционной системы.
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 399
Интерфейс с иными языками программирования
В SKW допускается подключение к Пролог-процессу функций язы-
языка Си. В Прологе каждая функция языка Си будет рассматриваться как
встроенный предикат. Механизм установления связи будет следующим.
Интерфейс между Си-функцией и Прологом задается в файле, имя кото-
которого имеет расширение « .pmi». В команде операционной системе "pmic"
в качестве аргумента указывается файл с расширением «.pmi». Эта ко-
команда генерирует файл с расширением «.ршо». Затем при помощи ко-
команды операционной системы "pld", ар1ументами которой служат файл
с расширением <(.рто» и соответствующий объектный Си-файл, порож-
порождается запомненное состояние Пролога. После восстановления запомнен-
запомненного состояния можно вызывать Си-функции через указанный интерфейс.
Расширения
В составе SKW имеется система управления реляционной базой дан-
данных, размещающейся на диске. Пролог-программы можно хранить на
диске в виде внешних баз знаний. Если внешняя база знаний подключена
к выполняющемуся Пролог-процессу, то ко всем фразам этой базы можно
обращаться точно так же, как и к загруженным обычным образом фразам
Пролога. Система SKW также может сопрягаться с некоторыми сущест-
существующими коммерческими реляционными базами данных.
Некоторые операции, выполняемые над фразами внешней базы знаний,
нельзя выполнить для фраз, загруженных в память. К примеру, встроенный
предикат "aggregate" выполняет операции подсчета суммы, среднего зна-
значения, максимума и минимума для одного аргумента предиката*), являю-
являющегося частью внешней базы знаний. Для аргументов предиката внешней
базы знаний можно также выполнить сопоставление с эталоном регулярных
(т.е. повторно встречающихся) выражений. Пусть, например, предикат
"служащий/3" является частью внешней базы знаний, подключенной к
текущему Пролог-процессу, а первый аргумент предиката "служащий/3" -
это атом, содержащий фамилию служащего. Тогда нижеследующий запрос
вернет значения аргументов всех фраз "служащий/3", в которых первый
аргумент заканчивается символами "Смит":
| ?- служащий( Фамилия ?:'Смит $ '._._)•
Фамилия = 'Вильям Г. Смит' ;
Фамилия = 'Сюзан Смит'
(Символ $ обозначает конец строки с регулярным выражением) .
В SKW имеется средство транзакций, которое позволяет программисту
превратить некоторые операции в атомарные. Смысл введения атомарной
*)Имеется в виду, что этот аргумент —список. —Примеч. пер.
400 ПРИЛОЖЕНИЯ
операции состоит в том, что либо она вся заканчивается удачно, либо
никакие ее действия не заканчиваются удачно. Средство транзакций будет
особенно полезным для программ, которые должны модифицировать
внешние базы знаний. Операции транзакций реализуются встроенными
предикатами "tbegin" (начало транзакции), "tcommit" (запуск транзак-
транзакции), "tabort" (прекращение транзакции), "detract" (отложенное удале-
удаление фраз) и "dessert" (отложенное добавление фраз). После обращения
к предикату "tbegin" никакие вызовы предикатов "dessert" или "detract"
не будут оказывать никакого перманентного влияния*) на внешнюю базу
знаний вплоть до обращения к предикату "tcommit". Вызов предиката
"tcommit" приведет к выполнению всех отложенных вызовов предикатов
"dessert" и "detract". Транзакции могут быть вложенными.
В SKW включено DCG-расширение, описанное в приведенном выше
разделе по Си Прологу.
Разное
Команда "plint" -- это команда операционной системы, позволяющая
проверить стиль Пролог-программы и обнаружить некорректности: одно-
однократно используемые переменные, предикаты, определенные более чем в
одном файле, и т.д. Команда операционной системы "plxref" позволяет
получить информацию о процессах, которые вызывают другие процеду-
процедуры из исходного Пролог-файла.
Пролог-2
Поставщик
Пролог-2 (Prolog-2) поставляется фирмой Эксперт Системз Интер-
Интернэшнл. Он работает под управлением операционной системы MS-DOS на
ЭВМ типа IBM PC или совместимых с ними.
Синтаксис и встроенные предикаты
Синтаксис Пролога-2 аналогичен синтаксису DEC-10 Пролога, хотя
есть и некоторые отличия. В Прологе-2 комментарии записываются между
обозначениями /*и * /, а символ % не является признаком комментария.
Директива записывается после символов ?—. После того как интерпре-
интерпретатор верхнего уровня найдет ответ на запрос, он печатает вслед за отве-
ответом сообщение-подсказку «more (у/п)Ъ) (еще? (да/нет)). Вводе дан-
данном месте символа "у" эквивалентен вводу точки с запятой в других
версиях Пролога. Это побуждает интерпретатор приступить к поиску дру-
другого ответа.
*) Имеется в виду то, что фразы внешней базы знаний останутся без изменений. —
Примеч. пер.
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 401
Все примеры данной книги работоспособны в среде Пролога-2, при
этом они не нуждаются в каких-либо модификациях. В Прологе-2 имеются
все встроенные предикаты DEC-10 Пролога. Они находятся либо в "ядре"
Пролога-2, либо в библиотеке, обеспечивающей совместимость с версией
DEC-10. Существует и много дополнительных встроенных предикатов.
Весь ввод-вывод Пролога-2 основывается на потоках. Обычные пре-
предикаты ввода-вывода ("see", "tell" и т.д.) автоматически создают и откры-
открывают потоки. Поток может быть окном (см. далее). Нижеследующие
встроенные предикаты обеспечивают более точное управление потоками.
create_stream (N, A, T, D)
TV должно быть уникальным именем потока. А — это код доступа:
«read» (чтение), << write» (запись) или « readwrite» (чтение и запись).
Т — тип данных, передаваемых потоком, —либо <<byte» (восьмибитовые),
либо « ascii» (семибитовые). D — это структура, описывающая поток.
Если D — структура "window/З" (окно/3), то предикат "create— stream"
образует новое окно в соответствии с параметрами этой структуры. В ка-
качестве D можно также использовать структуру "file/1", аргументом кото-
которой является имя файла.
open (N, А)
N — имя потока, созданного предикатом "create_stream". Л —коддоступа:
<<read», << write» или «readwrite». Встроенный предикат "ореп/2"
открывает названный поток для заданного типа доступа.
screen (V,C)
Для отображения окна на экране дисплея необходимо открыть для него
видеопорт (viewport). V — имя открываемого видеопорта. С —управляю-
—управляющая структура, указывающая, что необходимо сделать с этим видеопор-
видеопортом. Если С - структура "create/И" (создать/11), один из аргументов
которой — это имя окна, образованного при помощи встроенного преди-
предиката "create_ stream" и открытого предикатом "ореп/2", то предикат
"screen" откроет видеопорт для этого окна.
state (T, _,N)
Если окно было создано с помощью встроенного предиката"create_stream",
открыто при помощи предиката "ореп/2" и появилось на экране в резуль-
результате обращения к предикату "screen/2", то можно воспользоваться встроен-
встроенным предикатом "state/З" для связывания этого окна с текущим входным
и/или выходным потоком. (Помимо управления текущими входными вы-
выходным потоками, предикат "state/З" может выполнять и ряд других
402 ПРИЛОЖЕНИЯ
функций.) N — имя открытого потока, связываемого'с окном. Т — либо
«input» (входной),либо «output» (выходной).
close(N)
N - имя открытого потока. Этот предикат закрывает поток. Поток, одна-
однако, все еще продолжает существовать и его можно снова открыть при по-
помощи встроенного предиката "open/2". Если Л' — имя окна, то все ви-
видеопорты этого окна ликвидируются, а содержимое окна теряется.
delete—stream (N)
N — имя потока, созданного предикатом "create_stream". Встроенный
предикат "delete_stream" удаляет названный поток.
Арифметические функции
Арифметические операторы ("is", "< " и т.д.) в дополнение к обыч-
обычным арифметическим операциям будут вычислять и ряд функций, в число
которых в ходят:
sqrt (X) % квадратный корень из X
ехр (X) % число е в степени X
log (X) % натуральный логарифм X
ХЛУ% X в степени Y
length (X) % длина строки X
sin(X)
cos(X) *.'•
• tan(X) .!
asin(X)
acos (X)
atan (X) "..
и т.д.
Типы
Основные типы Пролога-2 — это атомы, целые числа, числа с плаваю-
плавающей точкой, структуры и строки.
Если все аргументы арифметического выражения являются целыми
числами, то в результате вычисления этого выражения получится также
целое число. Если в арифметическом выражении встречаются числа с
плавающей точкой, то результатом вычисления выражения будет число с
плавающей точкой. В результате выполнения операции деления / полу-
получится число с плавающей точкой, а в результате операции деления // —
целое число.
IV. ПЕРСИИ ЯЗЫКА ПРОЛОГ 403
Строки
Строки в Прологе-2 используются в большинстве таких ситуаций,
когда в других версиях этого языка применяются списки символов.
Символы, записанные внутри двойных кавычек, рассматриваются как
строка, а не как список символов. Поскольку строка имеет внутреннее
представление в виде массива символов, она занимает в памяти меньше
места, чем список символов*). Во многих случаях аргументами встроен-
встроенных предикатов Пролога-2 являются строки, а не списки символов, как в
других версиях этого языка. Примером такого предиката может служить
"name" (см. разд. 4.9) • Для работы со строками имеется специальный
встроенный предикат "is_ string/2". Вторым аргументом этого преди-
предиката должна быть одна из нижеследующих строковых функций, которую
данный предикат выполняет и результат которой возвращает через первый
аргумент.
Строковые функции
% сцепить две строки:
Х& Y
% вставить строку Y в строку X
% с позиции Р:
insert (X, Y, Р)
% удалить N символов из
% строки X с позиции Р
delete (X, Р, N)
% выделить N символов из
% строки X, после позиции Р:
substring (X, Р, N)
и т.д.
Пример
?—Z is_string substring (California, 2,4).
Z = "lifo"
Директивы
Важным моментом при проектировании модуля на языке Пролог-2
(см. ниже) является то, как в нем определяются предикаты — как общие
(public) или как приватные (private). К общему предикату можно обра-
обращаться извне данного модуля, а к приватному предикату — только в пре-
*) В списке дополнительная память тратится на указатели, связывающие друг с
другом его элементы. - Примеч. пер.
404 ПРИЛОЖЕНИЯ
делах этого модуля. По умолчанию, все предикаты модуля являются
общими. Все предикаты модуля можно превратить в приватные при
помощи директивы "private/0", не имеющей аргументов, либо в общие
по директиве "public/O". Конкретный предикат можно сделать приватным
при помощи директивы "private/1" или общим по директиве "public/1".
С целью осуществления оптимизации во время компиляции можно
при помощи директивы "mode" указать направленность аргументов преди-
предиката (входной или выходной аргумент). Например, в приводимом ниже
правиле "итог" первый аргумент всегда должен быть входным, а второй -
выходным:
% + - ' .
итог (клиент (_, Тариф, Дни), Сумма):-
Сумма is Тариф * Дни.
Директива "mode", информирующая компилятор о свойствах аргумен-
аргументов правила "итог", имеет вид:
? - mode итог (+, -).
Если программу нужно откомпилировать в объектный модуль, то
все обращения в исходном Пролог-файле к предикатам (не встроенным),
которые не определены в этом файле, должны объявляться при помощи
директивы "external".
Среда разработки программ
Среда Пролога-2 организована в виде модулей. Модулем может быть
либо Пролог-код, просмотренный интерпретатором, либо откомпилиро-
откомпилированный Пролог-код, либо объектный код программы, написанной на дру-
другом языке. Модули можно подключать к Пролог-процессу либо явно
(при помощи вызова встроенного предиката "open_module"), либо авто-
автоматически при запуске процесса. В Прологе-2 имеется свой механизм
виртуальной памяти, и частью спецификации модуля является указание
о том, где он должен находиться — целиком в реальной памяти или час-
частично в реальной и частично в виртуальной памяти. Виртуальная память
предоставляет возможность написания программ очень большого размера
за счет снижения скорости их выполнения. Многие вспомогательные прог-
программы, такие как интерпретатор верхнего уровня, текстовый редактор
и отладчик, реализованы в виде самостоятельных модулей, поэтому они не
занимают места в памяти, когда ими не пользуются.
Модули
Предикаты специфицируются внутри модуля либо как общие, либо
как приватные. К общим предикатам можно обращаться вне модуля,
в котором они определены, в то время как на приватные предикаты можно
ссылаться только внутри данного модуля. В каждый момент сеанса рабо-
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 405
ты с Прологом существует текущий выходной модуль и текущий вход-
входной модуль. Текущий выходной модуль — это модуль, куда помещаются
фразы, только что добавленные в программу-*
Редактор
В Прологе-2 имеется встроенный полноэкранный редактор, удобный
для внесения небольших изменений в существующие программы. После
запуска редактора на экран дисплея выводится список модулей, которые
можно редактировать. После выбора определенного модуля будет пока-
показан список предикатов этого модуля. После того как программист выбе-
выберет некоторый предикат, редактор выведет на экран текст всех фраз,
относящихся к предикату, и далее будет функционировать как редактор
текстов. В редактор заложена информация о синтаксисе Пролога, поэтому
он позволяет заранее обнаруживать синтаксические ошибки.
Отладчик
Отладчик Пролога-2 аналогичен отладчику СиПролога, но количество
команд у него значительно больше. После включения отладчика инфор-
информация, выдаваемая им, отображается в отдельном окне, поэтому нет опас-
опасности перепутать входные и выходные данные отладчика с входными и
выходными данными выполняющейся программы.
Компилятор
Компилятор Пролога-2 запускается при помощи встроенного предика-
предиката, но обрабатьшает внешний исходный файл и генерирует внешний объект-
объектный модуль. Отладчик не может работать со скомпилированным кодом.
Компилятор осуществляет индексацию (хеширование) первого аргумента
любого предиката, состоящего более чем из четырех фраз. Пользователь
может запретить эти действия при помощи директивы "hash/2".
Запомненные состояния
Команда «save_exe(File, Query)» переписывает Пролог-систему
и текущую базу данных в исполняемый файл и завершает текущий сеанс
работы с Прологом. При вызове исполняемого файла из среды операцион-
операционной системы осуществляется восстановление запомненного состояния и
выполнение запроса Query. Обратите внимание на то, что модуль верхнего
уровня интерпретатора Пролога не включается в запомненное состояние.
Интерфейс с иными языками программирования
В Прологе-2 имеются средства для подключения к Пролог-процессу
процедур, написанных на других языках программирования. Процедура
должна быть оттранслирована в объектный код н к объектному коду
должна быть добавлена специальная программа, вызывающая машинный
406 ПРИЛОЖЕНИЯ
код. Такие вызывающие программы существуют для нескольких языков
высокого уровня. Автоматическое отображение структур данных Пролога
на структуры данных других языков не выполняется. Вместо этого задает-
задается формат внутренних структур данных Пролога-2. Для того чтобы вос-
воспользоваться структурами данных Пролога-2, программист должен
написать соответствующие программы на других языках программи-
программирования.
Расширения
В Пролог-2 включено DCG-расширение, описанное в разделе по
СиПрологу.
Разное
В Прологе-2 имеется средство лексического анализа, сравнимое по гиб-
гибкости и мощности со вспомогательной программой "lex" операционной
системы UNIX- При помощи средства лексического анализа можно сос-
составлять программы обработки текстов, причем не нужно писать на Про-
Прологе саму программу лексического анализа (такую как программа "чи-
"читать предлож" из разд. 6.1).
Окна
В Прологе-2 имеется своя оконная система. Окно — это разновидность
потока. С окном можно производить такие же действия, как и с другими
типами потоков (т.е. с файлами и устройствами). Окно связано с буфе-
буфером, расположенным в оперативной памяти. Оно обладает такими характе-
характеристиками, как цвет, тип границы и т.д. Дтая того чтобы окно отображалось
на экране дисплея, следует открыть для него видеопорт при помощи
встроенного предиката "screen/2" (см. выше). Если на экране дисплея
отображаются одновременно несколько перекрьшающихся окон, то можно
управлять глубиной расположения каждого окна (т.е. тем, как далеко
оно находится от самого верхнего окна).
При помощи директивы "hash/З" можно задать индексацию первого
аргумента любого предиката интерпретируемого модуля.
В Прологе-2 обеспечивается оптимизация остаточной рекурсии (см.
подраздел "Разное" в приведенном выше описании Квинтус Пролога).
Оптимизацию можно включать или отключать с помощью обращения
к встроенному предикату "state/3".
В Прологе-2 имеется так называемый механизм сбора мусора, кото-
который при выполнении запроса автоматически пускает повторно в оборот
области оперативной памяти, которые один раз уже были использованы
и больше не нужны программе. Сущеавуют также встроенные предикаты,
предписывающие системе провести сбор мусора. Механизм сбора мусора
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 407
включается и выключается при помощи обращения к встроенному преди-
предикату "state/3".
Встроенный предикат "lint" осуществляет проверку синтаксиса и
стиля Пролог-программы, находящейся в исходном файле.
Эрити Пролог
Поставщик
Эрити Пролог (Arity Prolog) постаиляется фирмой Эрити Корпо-
Корпорейшн. Он работает под управлением операционной системы MS-DOS
на ЭВМ IBM PC или совместимой с ней.
Синтаксис и встроенные предикаты
Синтаксис Эрити Пролога аналогичен синтаксису DEC-10 Пролога.
Все примеры из данной книги будут работать в системе Эрити Пролог.
При этом, однако, для операционной системы MS-DOS в процедуре
"Вводполя" (см. разд. 3.9 и Приложение II) потребуется заменить
код символа перехода к новой строке с 10 на 13. Символ ! можно
использовать как синоним символа ; для соединения подцелей. В Эри-
Эрити Прологе имеется новая синтаксическая особенность, называемая
отрезком (snip). В составном запросе отрезком называется совокупность
подцелей, расположенных между сочетаниями символов [! и !]. Интерпре-
Интерпретатор не будет возвращаться назад ни для какой подцели, содержащейся
в отрезке. Это эквивалентно тому, как если бы все подцели, расположен-
расположенные внутри отрезка, выступали в роли аргументов предиката "один раз"
(см. разд. 3.2).
В Эрити Прологе есть большинство встроенных предикатов DEC-10
Пролога. Для управления файлами, помимо предикатов "see", "tell" и
т.д., описанных в разд. 3.5, имеются нижеследующие встроенные преди-
предикаты, в которых используются идентификаторы потоков (называемые
handles):
crcate(S, F) F — имя файла. S — идентификатор потока. Данный пре-
предикат создает новый файл для записи.
open(S, F, A) F — имя файла. S — идентификатор потока. А — режим
доступа к файлу: г, w , a, rw или га, где г означает чтение, и> — запись, а
а — запись в конец файла. Данный встроенный предикат открывает файл
с заданным режимом обмена информацией.
close(S) S — идентификатор потока, сгенерированный при обращении
к предикату "open" или "create".
Существуют варианты каждого стандартного предиката ввода-
вывода ("get", "read", "put", "write" и т.д.) с двумя аргументами, одним
из которых является идентификатор потока. Приведем пример, в котором
408 ПРИЛОЖЕНИЯ
считываются термы из файла,открыто го предикатом "open":
?- open (SI,'ар. data, r),
repeat,
read (SI, R),
обработка (R),
R = end_ of_ file,
close (SI).
Арифметические функции
Арифметические операторы (такие как "is", "< " и т.д.) позволяют
выполнять обычные арифметические операции и вдобавок вычислять ряд
друга х функций:
random % число между 0 и 1
abs (X) % абсолютное значение X ,
sqrt (X) % квадратный корень из X .•;,',
ехр(Х) %е в степени X .[[,.
log (X) % десятичный логарифм X ..
In (X) % натуральный логарифм X
XAY %Х в степени Y ' :
sin (X)
cos(X)
tan(X) i .; <
asin (X) . •¦¦"'"
acos(X) '¦;•.'.»'
atan(X)
и т.д. ¦ ¦ - "-
Типы
К основным типам Эрити Пролога относятся атомы, целые числа,
числа с плавающей точкой, структуры и строки. Альтернативной формой
записи списка символов служит запись символов между двойными ка-
кавычками.
Если все аргументы арифметического выражения являются целыми
числами, то и результат вычисления этого выражения будет целым числом.
Если в выражении попадаются числа с плавающей точкой, то в результате
вычисления выражения получится число с плавающей точкой. Результа-
Результатом операции деления / будет число с плавающей точкой, а результатом
операции деления // будет целое число.
Строки
Символы, записанные между знаками доллара, интерпретируются
как строка. В строку могут входить символы перевода строки. Поскольку
строка имеет внутреннее представление в виде массива символов, строки
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 409
занимают меньше места в оперативной памяти, чем списки символов.
Однако унификация строк выполяется значительно медленнее, чем уни-
унификация атомов. Строка не будет унифицироваться с атомом, содержа-
содержащим те же самые символы, но встроенный предикат "= = " рассматрива-
рассматривает как одинаковые строку и атом с одними и теми же символами.
?- $california$ = California.
нет
?- $california$= = California.
да
Нижеследующие встроенные предикаты специально предназначены
для работы со строками:
% ввод-вывод:
read_string (МаксДлина, Строка)
%из текущего входного потока
read_string (S,МаксДлина, Строка)
% из потока S
reacLline (S, Строка) % из потока S
write (Строка) % как и write (Атом)
% преобразование:
string-term (Строка, Терм)
atom_ string (Атом, Строка)
int_ text (Целое, Строка)
float-text (Плавающее, Строка)
list-text (Список, Строка) % [97,98] в$аЬ$
% другое:
string—search (Шаблон, Строка, Позиция)
substring (Строка, Позиция, Длина, Подстрока)
string-length (Строка, Длина)
concat (SI, S2, S3) % S3 - это SI,сцепленная с S2
Среда разработки программ
Эрити Пролог обладает следующими двумя особенностями, которые
облегчают разработку больших программ: 1) наличие виртуальной памя-
памяти и 2) возможность разделения программы на сегменты*)- Программа-
менеджер, управляющая взаимодействием с виртуальной памятью выпол-
выполняет обмен между оперативной памятью и диском. Размер страницы —
16 К. Сегмент может состоять из 256 страниц, в одной программе может
*) В оригинале - worlds (миры). - Примеч. пер.
410 ПРИЛОЖЕНИЯ
быть до 256 сегментов. В отличие от модуля Пролога-2, сегмент Эрити Про-
Пролога служит лишь средством организации фраз в программе. Сегмент
нельзя присоединять к различным программам и отсоединять от них.
Существуют две разновидности сегментов — сегмент данных и сегмент
кода. Сегмент данных целиком состоит из баз данных, образованных
из фактов. Факт добавляется в текущий сегмент данных при помощи
любого из встроенных предикатов "recorda", "recordz", "record—after"
или "replace", а удаляется из текущего сегмента данных предикатом
"erase". Сегмент кода состоит из предикатов, в которые могут входить
и факты, и правила. Фраза добавляется в текущий сегмент кода при
помощи предиката "assert", а удаляется из него предикатом "retract"
(см. разд. 4.7).
По умолчанию во время сеанса работы с Прологом всегда сущест-
существует сегмент (предназначенный и для кода, и для данных), назы-
называемый "api". Новый сегмент создается при обращении к встроенному
предикату "create—world". После того как сегмент будет создан, вызов
предиката "data_world" превратит его в текущий сегмент данных (т.е.
это будет сегмент, к которому применимы действия "erase", "recorda"
и т.д.). Вызов встроенного предиката "code_world" превратит создан-
созданный сегмент в текущий сегмент кода (т.е. для этого сегмента станут
допустимы действия "assert" и "retract"). Для оптимизации использова-
использования виртуальной памяти программист может поместить все предикаты,
относящиеся к определенной"~теме, в один сегмент, а когда потребуется
опросить предикаты этого сегмента, программист может превратить этот
сегмент в текущий. Обращение к встроенному предикату "delete-world"
приведет к удалению сегмента со всеми его фразами.
edit (F)
Встроенный предикат "edit" имеет единственный аргумент — имя
файла. Данный предикат обращается к переменной среды DOS "editor",
которая содержит имя редактора. Затем предикат "edit" приостанавли-
приостанавливает Пролог-процесс и запускает внешний редактор для корректировки
файла. После окончания редактирования предикат "edit" возобновляет
выполнение Пролог-процесса и автоматически инициирует повторный
просмотр файла. (Смысл термина "повторный просмотр" ("reconsult")
будет тем же самым, что и для СиПролога).
Отладчик
Отладчик Эрити Пролога в целом аналогичен отладчику СиПролога.
Строку отладочной информации:
{api, api) ** @) CALL: полет (пипаз, -0039, -0040) 1 >
можно рассматривать следующим образом.
{((api, api) » - это имена сегмента кода и сегмента данных,
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 411
** означает, что в данный момент контрольная точка установлена
в процедуре "полет/3".
@) — это уникальное обозначение конкретного вызова данной про-
процедуры.
«C4Z,/,:» показывает, что эта информация относится к месту перво-
первоначального входа в процедуру.
((полет (пиплз, -0039, -0040) » - сама подцель.
? > — это сообщение—подсказка, свидетельствующее о том, что отлад-
отладчик ожидает ввода отладочных команд.
У отладчика Эрити Пролога имеется значительно большее число отла-
отладочных команд, чем у отладчика СиПролога.
Компилятор
Для Эрити Пролога существует компилятор.
Запомненные состояния
При помощи встроенного предиката "save/О" можно запомнить все
изменения сегментов программы, сделанные после предыдущего обраще-
обращения к этому предикату. Изменения запоминаются в двоичном файле.
Встроенный предикат "restore/O" ликвидирует все изменения текущей
программы, сделанные после последнего обращения к предикату "save/0".
Аргументом встроенного предиката "save/1" является имя файла.
Предикат "save/1" позволяет запомнить двоичный образ текущего состоя-
состояния интерпретатора Пролога. Этот предикат помещает фразы каждого сег-
сегмента в отдельный файл. В качестве аргумента встроенного предиката
"restore/1" используется имя файла, которое ранее употреблялось при
обращении к предикату "save/1". Предикат "restore/1" восстанавливает
состояние интерпретатора Пролога, описанное в файле.
Расширения
В Эрити Пролог включено DCG-расширение, которое было описано
выше в разделе, посвященном СиПрологу. Среди других расширений
можно назвать одну из версий языка запросов к базе данных SQL и пакет
для разработки экспертных систем.
Разное
В Эрити Прологе имеются два способа увеличения скорости доступа
к базам данных, состоящим из фактов, —индексацияпри помощи Ь-дерева
и индексация с помощью хеш-таблицы.
В-деревья
Для того чтобы хранить базу данных, состоящую иэ фактов, в отсорти-
отсортированном по значениям одного из аргументов виде, можно воспользовать-
воспользоваться b-деревом. Новые факты добавляются в базу данных при помощи
412 ПРИЛОЖЕНИЯ
встроенного предиката «recordb (Дерево, ПолеСортировки, Факт)»,
где «Дерево» - имя дерева, «Факт» - факт, а «ПолеСортировки» -
один из аргументов переменной «факт». Если « Дерево» пока не сущест-
существует, то оно будет создано этим предикатом. Обратите внимание на то, что
база данных, созданная предикатом "recordb", не имеет такой же формы,
как множество фактов программы,икней нельзя непосредственно адресо-
адресовать запросы. Все запросы к такой базе должны направляться через встроен-
встроенный предикат "retrieveb/З", аргументы которого будут точно такими же,
как и у предиката "recordb/З". Факт можно удалить из базы данных посред-
посредством обращения к встроенному предикату "removeb/З". .
Хеш-таблицы
Для хранения базы данных в гаком виде, чюбы все факты с одинако-
одинаковыми значениями одного из аргументов располагались вместе, можно вос-
воспользоваться хеш-таблицей. Хеш-таблица может значительно повысить
эффективность выполнения запроса к базе данных, если хешируемый
аргумент конкретизируется в запросе. Новые записи добавляются в базу
данных при помощи встроенного предиката « recordh (Таблица, Поле-
ПолеСортировки, Факт))), где « Таблица)) - имя таблицы, ((.Факт)) -это факт,
а ((ПолеСортировки)) — один из аргументов Факта. Если ({Таблица))
еще не существует, то она создается данным предикатом. База данных,
созданная встроенным предикатом "recordh", не выглядит как множест-
множество фактов программы, и к ней нельзя непосредственно адресовать запросы.
Все запросы к такой базе следует направлять через встроенный предикат
"retrieveh/З". Удалить факт из базы данных можно при помощи встроен-
встроенного предиката "removeh/З". В других версиях Пролога хеш-таблицу
можно построить только для первого аргумента фразы, а в Эрити Проло-
Прологе встроенные предикаты хеширования позволяют строить хеш-таблицу
для любого аргумента.
В Эрити Прологе имеется механизм.сбора мусора, который автома-
автоматически вступает в работу, когда число доступных блоков стековой памя-
памяти снижается до критического значения. Этот механизм можно также
запустить явно при помощи обращения к встроенному предикату "gc".
УНСВ Пролог
Поставщик
УНСВ Пролог (UNSW - сокращение от "University of New South
Wales", что означает "Университет Нового Южного Уэльса") — зто версия
языка, являющаяся общественной собственностью. Она работает почти
на всех компьютерах с операционной системой UNIX- Ее можно получить
у лиц, уже имеющих исходный текст УНСВ Пролога. Пролог-86
(Prolog-86) — это версия УНСВ Пролога для операционных систем MS-DOS
и СР/М. Эта версия Пролога поставляется фирмой MICRO-AI. Пролог-86
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 413
работает на ЭВМ IBM PC и совместимых с ними вычислительных машинах.
В Прологе-86 можно пользоваться лишь ограниченным объемом памяти,
но зато скорость выполнения программ очень^высока. Халцедони Пролог
(Chalcedony Prolog) — это версия УНСВ Пролога для операционных систем
MS-DOS и Apple Macintosh, поставляемая фирмой Chalcedony.
Синтаксис и встроенные предикаты
Синтаксис Пролога-86 в основном аналогичен синтаксису DEC-10
Пролога, но имеются и некоторые важные различия. Для того чтобы было
можно воспользоваться программами, приведенными в данной книге,
рекомендуется модифицировать файл "prolog.lib" (или "prolog_lib"),
поставляемый вместе с Прологом-86, включив в него библиотеку, обеспе-
обеспечивающую совместимость с DEC-10. Текст этой библиотеки приводится
в конце раздела. Если этой библиотеки не будет, то многие из программ
данной книги придется доработать, чтобы они смогли работать в среде
Пролога-86 (например, будет нужно модифицировать списки символов).
Сообщение-подсказка верхнего уровня в Прологе-86 - это символ : .
Если в ответ на подсказку пользователь введет фразу, заканчивающуюся
точкой, то это будет воспринято как добавление фразы в программу, а
не как запрос. Введенная фраза будет добавлена к множеству фраз теку-
текущей программы. Для того чтобы получился запрос к текущему множест-
множеству фраз, пользователь должен набрать фразу, оканчивающуюся вопроси-
вопросительным знаком. Принятый подход очень удобен для занесения фраз в прог-
программу в диалоговом режиме (когда пользователь не должен выдавать
команду « consult (user)» для того, чтобы вводить новые фразы), но мо-
может привести к путанице, если пользователь привык к иным версиям
Пролога.
Если пользователь введет запрос, содержащий переменные, то
Пролог-86 автоматически напечатает все значения переменных, при кото-
которых запрос будет истинным, не делая после каждого ответа пауз в ожида-
ожидании того, что пользователь наберет символ ;. Это создаст неудобства в
случае, если ответов будет настолько много, что они все не поместятся
на экране; При этом первые ответы могут пропасть с экрана до того, как
выполнение запроса закончится. Ситуация станет особенно острой, если
запрос будет обладать бесконечным количеством ответов. Наилучшим
выходом из создавшегося положения будет написание интерпретатора
верхнего уровня. Аргументом такого интерпретатора служит запрос, а
после выдачи каждого ответа на запрос интерпретатор должен делать
паузу.
Основная форма записи конструктора списка в Прологе-86 такова:
[a,b,..R].
Это означает то же самое, что и:
[a, b | R]
414 ПРИЛОЖЕНИЯ
Пролог-86 воспринимает и символ \ как конструктор списка, но этот
символ будет преобразован в сочетание символов ". . ". Дня связи подце-
подцелей можно воспользоваться символом ! как синонимом символа ;.
В Прологе-86 имеются некоторые предикаты DEC-10 Пролога, а также
и ряд дополнительных предикатов. Встроенные предикаты, предназначен-
предназначенные для работы с символами, рассматриваются ниже в подразделе "Типы".
В Прологе-86 предикат "consult" означает то же самое, что и в СиПро-
логе. Все файлы, названия который задаются в командной строке при вызо-
вызове Пролога-86 из среды операционной системы, будут автоматически
просмотрены. Предикат "load" в Прологе-86 означает то же самое, что и
"reconsult"e СиПрологе.
Встроенный предикат "ratom" считывает из входного потока один
атом и, в отличие от встроенного предиката "read", не требует, чтобы
после атома стояла точка. Встроенный предикат "print" печатает любое
количество аргументов и затем вьшолняет переход к новой строке, а
встроенный предикат "prin" печатает любое количество аргументов, после
чего не переходит к новой строке.
Арифметические операторы ("is", "< " и т.д.) воспринимают символ
" " " как обозначение операции. Выражение 2 л 3 означает два в третьей
степени.
Типы
Основные типы Пролога-86 — это атомы, целые числа, структуры и
символы. Вместо предиката ввода "getO", который вырабатывает значе-
значение ascii-кода символа из текущего входного потока, в Прологе-86 есть
встроенный предикат "getc", который вводит символ из текущего вход-
входного потока. Вместо предиката "put", аргументом которого является
значение ascii-кода выводимого символа, в Прологе-86 есть встроенный
предикат "putc", аргументом которого является выводимый символ.
Встроенный предикат << ascii (Символ, Код))) преобразует символ в его
ascii-код и наоборот. В отличие от других версий Пролога, где вторым
аргументом встроенного предиката "name" является список ascii-кодов
(см. разд. 4.9), в Прологе-86 вторым аргументом предиката "name" служит
список символов, который преобразуется в атом или обратно. (Ниже
рассказывается, как в Прологе-86 можно определить версию предиката
"name", эквивалентную предикату "name" других версий Пролога.)
В отличие от СиПролога, символы, записанные между двойными ка-
кавычками, интерпретируются как атом (т.е. так же, как и символы между
апострофами), а не как альтернативная форма представления списка сим-
символов .
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 415
Директивы
Если пользователь поставит в конце запроса восклицательный знак,
то этот запрос будет выполнен, но никакаягвыходная информация при
этом не будет выводиться. Запрос, после которого стоит восклицатель-
восклицательный знак, называется << командой)). При просмотре файла интерпретатор
трактует содержимое файла точно так же, как если бы оно непосредствен-
непосредственно вводилось пользователем. Так, если факт в файле исходного текста
заканчивается вопросительным знаком, то при просмотре этого файла
данный факт будет рассматриваться как запрос, который будет выполнен
до того, как интерпретатор перейдет к просмотру остальной части файла.
Если факт завершается восклицательным знаком, то этот факт будет
выполнен как команда (т.е. ие будет выдаваться никакой выходной инфор-
информации) до перехода к просмотру оставшейся части файла. Интерпретатор
будет также рассматривать как команду и запрос, перед которым стоят
символы :- и который заканчивается точкой.
Среда разработки программ
В Прологе-86 отсутствует встроенный редактор, поэтому при разра-
разработке программ программисту придется воспользоваться средствами
операционной системы.
В УНСВ Прологе имеется встроенный предикат "ed/1", обеспечиваю-
обеспечивающий переход к редактированию процедуры во время сеанса работы с
Прологом. Перед запуском Пролога следует определить имя редактора
операционной системы UNIX при помощи переменной "EDITOR" интер-
интерпретатора команд "shell" этой операционной системы. Для редактирования
программы во время сеанса работы с Прологом вызывается предикат
"ed/1", в качестве аргумента которого задается имя определенной в дан-
данный момент процедуры. Предикат "ed/1" перепишет все фразы указан-
указанной процедуры во временный файл, а затем запустит заданный редактор
для корректировки временного файла. При этом редактор будет про-
процессом-потомком Пролог-процесса. После окончания сеанса редактирова-
редактирования старые фразы процедуры заменяются на фразы из временного файла,
а сам временный файл уничтожается.
Отладчик
Отладчик Пролога-86 отдаленно напоминает отладчик СиПролога.
Однако в Прологе-86 отсутствуют контрольные точки, нет диалоговых
отладочных команд и нет возможности проследить за выполнением всех
процедур, не указывая их имена. Отладчик включается при помощи вызова
предиката "trace/1", аргументом которого является имя одной процеду-
процедуры или список имен процедур. Когда при выполнении запроса встречаются
трассируемые процедуры, отладчик печатает информацию о них в стандарт-
стандартных четырех точках: call (вызов), exit (выход), fail (неудача) и redo(noe-
416 ПРИЛОЖЕНИЯ
торное выполнение). В сообщениях отладчика отсутствует уникальная
идентификация вызова процедуры, однако при помощи символов | , рас-
располагающихся перед самой подцелью, показывается количество предков
этой подцели. Тем самым при выполнении запроса к рекурсивной проце-
процедуре получается интересное графическое представление. Пример выход-
выходной информации, выдаваемой при запросе к предикату "member":
: trace member?
**да
: member(a, [с, b, a])?
С I > member(a, [с, b, a])
С | i> member (a, [b, a])
С ! ! ] > member (a, [a]) •
Е ! | | < member (а, [а])
Е ! | < member (a, [Ь, а])
Е | < member(a, [с, Ь, а]) . - .
* * да
Символ С, стоящий в начале строки, обозначает тсЛку вызова, а сим-
символ Е - точку выхода. и
Компилятор ;'
Для Пролога-86 нет компилятора. |i
Запомненные состояния ^
В Прологе-86 нет ничего похожего на двоичные запомненные состояния
СиПролога. Встроенный предикат "save/1", аргументом которого является
имя файла, переписывает в файл в форме, доступной для восприятия чело-
человеком, все фразы текущей программы. При этом, если во фразах есть пере-
переменные, то они будут представлены своими внутренними именами.
Интерфейс с иными языками программирования
Если в Вашем распоряжении имеется исходный текст УНСВ Пролога,
то в него можно добавить в качестве дополнительных встроенных предик*-
тов функции, написанные на языке Си.
Разное
Имеется встроенный предикат "еоР, который будет истинным, если
встретится состояние "конец файла" для текущего входного потока.
Ниже приводится текст библиотеки, обеспечивающей совместимость
Пролога-86 с DEC-10 Прологом, что позволит выполнять в Прологе-86
программы из данной книги.
% Библиотека совместимости для
% Пролога-86. Добавьте ее в файл
% "prolog. lib" или "prologjib"
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ ¦ 417
% вместо встроенного предиката "name"
% пользуйтесь нижеследующие предикатом:
declOname (Атом, ИСписок) : —
nonvar (ИСписок),
char list (ИСписок, ССписок),
name (Атом, ССписок),!.
declOname (Атом, ИСписок) : -
atom (Атом),
' name (Атом, ССписок),
char list (ИСлисок, ССписок),!.
getO(I): - getc(C), ascii(C, I), !.
put (I):- ascii(C, I), putc(C),!.
:- opG00,xfy, = <).
X = <Y:-X<=Y.
:- opG00,xfx, = =).
X = = Y:- not(X=Y).
Турбо Пролог
Поставщик
Турбо Пролог поставляется фирмой Борленд Интернэшнл. Он работает
под управлением операционной системы MS-DOS на ЭВМ IBM PC и совмес-
совместимых с ними компьютерах.
Турбо Пролог - это компилятор (не интерпретатор!). Он отличается
высокой скоростью компиляции и выполнения. Среда разработки прог-
программ Турбо Пролога на первый взгляд кажется превосходной, но на са-
самом деле это не совсем так. Программа, написанная на Турбо Прологе,
сильно отличается от других Пролог-программ, так как она всегда должна
начинаться с директив компилятора. Общий вид программы:
trace /* по желанию */
project "название проекта" / * по желанию */
include "другой _исходный_файл"/* по желанию */
domains /* по желанию; объявляет */
лицо = symbol /* новые типы областей значений */
смена = symbol
database /* по желанию; */
работает (лицо, смена) /* объявляет преди- */
/* каты, которые можно */
/ * добавлять и удалять •/
predicates /* обязательно, объявляет */
знает (лицо, лицо) /* область */
/ * каждого аргумента) */
14. Дж. Малпас
418 ПРИЛОЖЕНИЯ
goal /* по желанию */
знает (А, В).
clauses /* как правило, необходимо; */
/* здесь располагается сам * /
/* текст программы */
работает (билл,дневная),
работает (нэнси, дневная).
знает (X,Y) :-
работает(Х,Б),
работает (Y, S),
XOY.
Если в программе есть директива "goal" (цель), то при выполнении
программы система прогона вычислит эту цель один раз и закончит прог-
программу. Если в программе нет директивы "goal", то во время выполнения
программы пользователь может вводить запросы. Смысл других директив
излагается ниже.
Синтаксис и встроенные предикаты
Синтаксис Турбо Пролога в значительной мере аналогичен синтаксису
DEC-10 Пролога. Многие программы данной книги без каких-либо переде-
переделок будут работать под Турбо Прологом.
В качестве синонима символического обозначения : - можно использо-
использовать слово "if (если), вместо ; можно использовать слово "or" (или),
а вместо , — слово "and" (и). Комментарии в Турбо Прологе записывают-
записываются между символами / * и * /. Символ % не является признаком коммен-
комментария .
В Турбо Прологе имеются некоторые встроенные предикаты, анало-
аналогичные предикатам DEC-10 Пролога.
Приведем встроенные предикаты Турбо Пролога, эквивалентные не-
некоторым часто используемым встроенным предикатам DEC-10 Пролога:
DEC-10 пролог
Турбо Пролог
Пояснения
is/2 =/2 арифметическое вычисление
var/1 free/1 успешен, если аргументом является
неконкретизированная переменная
nonvar/1 bound/1 успешен, если аргументом не является
неконкретизированная переменная
\= =/2 < >/2 успешен, если аргументы не одинаковы
getO/1 readchar/1 считывает символы с текущего
входного устройства
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 419
В Турбо Прологе отсутствует предикат, эквивалентный предикату
" =/2" DEC-10 Пролога (этот предикат унифицирует два любых терма).
В Турбо Прологе невозможно определить операции.
В Турбо Прологе имеются встроенные предикаты "asserta", "assertz"
и "retract", предназначенные для модификации текущей программы. Од-
Однако, в отличие от других описанных здесь версий Пролога, аргументами
этих трех предикатов должны быть только факты, а не правила. Любой
предикат, фразы которого предполагается удалять и добавлять, должен
быть объявлен как предикат базы данных при помощи директивы ком-
компилятора "database". К примеру, предикат "работает/2" объявлен в при-
приведенном выше участке исходного файла как предикат базы данных.
У встроенного предиката "write" может быть любое число аргументов.
Существует встроенный предикат "writef", первым аргументом которого
должна быть строка форматов. После первого аргумента может распо-
располагаться произвольное количество других аргументов. В Турбо Прологе
отсутствует предикат, эквивалентный встроенному предикату "read/1"
DEC-10 Пролога, но имеются предикат "readln/1", считывающий строку
символов, и предикат "readterm/2", который считывает терм. Первым ар-
аргументом встроенного предиката "readterm/2" должна быть спецификация
области значений, которая определяет то, какие типы термов может счи-
считывать данный предикат (см. ниже подраздел о типах).
Вместо встроенных предикатов "see", "tell" и т.д. в Турбо Прологе
имеются следующие предикаты, предназначенные для управления фай-
файлами:
openread(N, F)
openwrite(N, F)
openappend(N, F)
openmodify(N, F)
Здесь F — имя файла в операционной системе MS-DOS, TV — внутрен-
внутреннее имя, выбранное программистом, которое будет использоваться при
обращении к открытому файлу. Встроенный предикат "openread" открыва-
открывает файл для чтения. Встроенный предикат"openwrite" открывает файл для
записи. Встроенный предикат "openappend" открывает файл для добав-
добавления записей в конец файла. Встроенный предикат "openmodify" открыва-
открывает файл и для чтения, и для записи. В файл произвольного доступа можно
внести изменения, если он открыт при помощи встроенного предиката
"openmodify", а для позиционирования указателя записи используется
встроенный предикат "filepos/3".
writedevice(N)
N — внутреннее имя файла, открытого при помощи встроенного пре-
предиката "openwrite", "openmodify" или "openappend". Этот предикат соот-
14*
420 ПРИЛОЖЕНИЯ
носит файл с текущим устройством вывода, так что выходная информа-
информация, вырабатываемая при любых вызовах встроенного предиката "write"
или "writef", пойдет в этот файл.
readdevice(N)
jV — внутреннее имя файла, открытого при помощи встроенного преди-
предиката "openiead". Этот предикат соотносит файл с текущим входным уст-
устройством, так что информация, вводимая при любых обращениях к встро-
встроенным предикатам "readchar/1", "readln/1", "readint/1", "readreal/1" или
"readterm/2", будет поступать из этого файла.
closefile(N)
jV -внутреннее имя открытого файла. Данный встроенный предикат
закрывает этот файл.
Арифметические функции
Арифметические операторы ("=", "<" и т.д.) в дополнение к обыч-
обычным арифметическим операциям позволяют вычислять ряд функций, сре-
среди которых в первую очередь нужно отметить следующие:
abs(X) % абсолютное значение X
sqrt(X) % квадратный корень из X
ехр(Х) % число е в степени X
log(X) % десятичный логарифм X
1п(Х) % натуральный логарифм X
sin(X)
cos(X)
tan(X)
arctan(X)
и гд.
Типы • ч
Турбо Пролог отличается от других версий Пролога тем, что в нем
должен быть объявлен тип области значений (domain type) для всех
аргументов каждого предиката. В Турбо Прологе изначально имеются
нижеследующие простые типы области значений:
char
integer
real
string
symbol
file
К типу «char» относятся одиночные символы, к типу «symbol» — атомы.
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 421
Типы «string» и «symbol» взаимозаменяемы, хотя они и имеют различное
внутреннее представление. Приведем простой пример, показывающий, как
можно определить новые типы области значений через простые типы и как
типы области значений употребляются в объявлениях предикатов:
domains
имя = symbol
predicates
сделка (имя, real)
clauses v
сделка (боб, 37.50).
сделка (мери, 4.75).
сделка (сью-элеи, 50.00).
Поскольку в объявлении области значений записано «имя = symbol», «имя»
становится новым типом области значений, совпадающей с областью «sym-
«symbol». Если при выполнении данной программы пользователь попытается
воспользоваться запросом к предикату "сделка", задавая неверные типы
области значений, то Турбо Пролог выдаст сообщение Об ошибочном ис-
использовании типов области значений.
Структуры можно определять как новые типы области значений,
выражая их через простые типы области значений. Приведем версию прог-
программы "сделка" из разд. 2.2. Оба аргумента предиката "сделка" являются
структурами.
domains
имя = symbol
сумма = integer
структура_клиент = клиент (имя, сумма, integer)
структура_дата = дата (integer, integer, integer)
predicates
сделка (структура—клиент, структура—дата)
clauses
сделка (клиент (смит, 29,4), дата (87,4,22)).
сделка (клиент (ли, 35,7) , дата (86,1030)).
Если одним из аргументов предиката является список, то область зна-
значений этого аргумента следует объявить как объект*, где «объект» — это
область значений каждого элемента списка. Приведем в качестве примера
версию процедуры "member", которая будет работать со списком, вклю-
включающим целые числа:
domains
список_целых = integer*
predicates
member(integer, список—целых)
422 ПРИЛОЖЕНИЯ
clauses
member (X, [X | _]).
member (X, [_ \ Y]) :- member (X, Y).
В данной программе проявляется недостаток принятой в Турбо Проло-
Прологе строгой типизации: если пользователь напишет запрос к процедуре
"member", аргументом в котором будет список, содержащий атомы, дей-
действительные числа или структуры, то Турбо Пролог выдаст сообщение об
ошибочном использовании типа области значений и не будет выполнять
программу. На практике это означает, что программист должен предусмот-
предусмотреть заранее, элементы каких типов могут попадаться в списке, который
будет аргументом процедуры "member", и включить их в объявление
областей значений. Тем самым необходимость объявления областей зна-
значений существенно уменьшает потенциальную возможность использова-
использования составленной программы в каких-либо других целях. Помимо этого,
становится невозможным написание предикатов-метаязыка, см. ниже под-
подраздел 'Тазное".
Очевидно, что объявления типов областей значений сильно влияют на
работу алгоритма унификации в Турбо Прологе. Вообще говоря унифика-
унификация терма, находящегося в запросе, с термом из фразы программы может
произойти только в том случае, если во время компиляции программы эти
термы были объявлены с совместимыми типами области значений.
Ctpqku
Перечислим имеющиеся в Турбо Прологе встроенные предикаты, пред-
предназначенные для работы со строками.
readln (Строка)
Этот предикат считывает запись данных с текущего входного устрой-
устройства и возвращает ее в виде строки.
frontchar (Строка, ПервСимв, Остаток)
Этот предикат берет первый символ из начала строки и возвращает
оставшуюся часть строки через «Остаток».
frontstr(N, Строка, Начало, Конец)
Здесь jV — целое число, «Строка» — это строка по меньшей мере из
N символов. Данный предикат возвращает первые N символов строки
«Строка» через переменную «Начало» (которая также является строкой),
а остальные символы строки «Строка» - через переменную «Конец».
fronttoken(Строка, Признак, Остаток)
Если переменная «Строка» конкретизирована, то данный предикат на-
находит первое слово или число, содержащееся в переменной «Строка», и
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 423
возвращает его через переменную «Признак». Остаток строки возвраща-
возвращается через переменную «Остаток».
str_len (Строка, Длина)
Данный предикат возвращает число символов, содержащихся в стро-
строке «Строка».
Преобразование типов
В Турбо Прологе имеются нижеследующие встроенные предикаты,
предназначенные для преобразования значений от одного типа к другому:
str_char (Строка, Символ)
str_int (Строка, Целое)
str_real (Строка, Действительное)
/* преобразовать ascii-код в соот- */
/* ветствующий ему символ: */
char_int (Символ, Целое)
/* преобразовать строку, приведя ее */
/* целиком либо к буквам верх- */
/* него регистра (заглавные буквы), */
/* либо к буквам нижнего ре - */
/* гистра (строчные буквы) */
upper_lower (. Верх—Строка, Ниж_Строка)
Среда разработки программ
После запуска Турбо Пролога на экране дисплея образуются четыре
окна, размеры которых можно изменять: окно редактора; окно диалога,
через которое осуществляется обмен данными с выполняющейся програм-
программой; окно сообщений, в котором выдаются предупреждающие сообщения
компилятора и т.д., и окно трассировки, в котором отображается выход-
выходная информация отладчика. Командная строка, располагающаяся в верхней
части экрана, действует подобно меню высокого уровня. С помощью этой
строки легко переходить от написания программы к ее компиляции и вы-
выполнению .
Компилятор Турбо Пролога может создавать объектные файлы, кото-
которые поддаются редактированию при помощи редактора связей операцлон-
ной системы MS-DOS. Так, можно написать большую программу в виде
множества модулей, а затем связать их в одну выполняемую программу.
Можно управлять интерфейсом между модулями при помощи объявления
глобальных областей значений и глобальных предикатов (т.е. предикатов,
к которым можно обращаться за пределами модуля, в котором они опре-
определяются). Программа, состоящая более чем из одного модуля, называет-
называется проектом. Проект определяется в файле библиотекаря. Каждый исход-
424 ПРИЛОЖЕНИЯ
ный файл, являющийся частью проекта, должен иметь в своем составе
директиву компилятора "project" (см. выше первый пример исходного
файла).
Отладчик
Отладчик Турбо Пролога включается директивой компилятора "trace",
располагающейся в исходном файле. Если эти директива задана, то при вы-
выполнении программы будет осуществляться трассировка всех предикатов,
содержащихся в файле. Трассировку можно включать и отключать при помо-
помощи запроса к встроенному предикату "trace/1". В окне трассировки будут
отображаться сообщения отладчика, которые аналогичны сообщениям,
выдаваемым отладчиком СиПролога. Параллельно с выдачей сообщений
отладчик позиционирует курсор в окне редактирования на фразу, которая
в данный момент выполняется. Это очень удобно, так как непосредственно
кидно, какое место программы сейчас выполняется.
Запомненные состояния-
В Турбо Прологе нет ничего похожего на двоичные запомненные состоя-
состояния СиПролога. Аргументом встроенного предиката "save/1" является имя
файла. Этот предикат переписывает в файл в форме, воспринимаемой че-
человеком, все факты текущей программы, относящиеся к предикатам базы
данных. (Предикат объявляется как предикат базы данных посредством
директивы компилятора "database"; см. выше первый пример исходного
файла.) Обратите внимание на то, что файл, создаваемый встроенным пре-
предикатом "save/1", не является исходным файлом Пролога и его нельзя
компилировать. Факты из этого файла можно считать назад в текущую
программу, если обратиться к предикату "consult/1".
Интерфейс с иными языками программирования
Турбо Пролог позволяет подсоединять к Пролог-программе процеду-
процедуры, написанные на языках Паскаль, Си, Фортран или ассемблер. Процедуры,
написанные на этих языках, следует объявлять в Пролог-программе как гло-
глобальные предикаты. После того как Пролог-программа и процедуры, на-
написанные на других языках программирования, будут оттранслированы в
объектные модули, можно воспользоваться редактором связей операцион-
операционной системы MS-DOS для того, чтобы связать их в выполняемую програм-
программу. Существуют средства для отображения структуры данных перечислен-
перечисленных языков на структуры данных Пролога и обратно, что позволяет реали-
реализовать передачу аргументов.
Расширения
В Турбо Пролог включены расширения, обеспечивающие экранно-
ориентированный ввод-вывод, управление цветом, окнами и звуком,
и средства для работы с графопостроителем "черепашка".
IV. ВЕРСИИ ЯЗЫКА ПРОЛОГ 425
Разное
Если во время компиляции в программе^отсутствует директива ком-
компилятора "'trace", то компилятор осуществит оптимизацию остаточной ре-
рекурсии в тех рекурсивных процедурах, которые являются детерминиро-
детерминированными при вызове рекурсивной подцели.
Из-за принятой в Турбо Прологе строгой типизации ни один из преди-
предикатов метауровня ("одинраз", найти _или_спросить", "послать", и т.д.)
не будет работать так, как это описывалось в книге. Посмотрим, как на
Турбо Прологе можно было бы реализовать простейший пример предика-
предикатов метауровня - предикат "один_раз" (см. разд. 3.2). Обычный текст
предиката "один_раз" таков:
один^раз (Р) : -
Р, ! •
Прежде всего отметим, что компилятор Турбо Пролога не допускает
употребления переменной в качестве подцели. Далее заметим, что все
возможные аргументы предиката "один_раз" должны быть указаны в
объявлении этого предиката. Пусть программа содержит предикаты "зна-
"знает/2" и "работает/2". Предположим, что нам нужно, чтобы "один_раз"
можно было использовать при выполнении программы совместно с каж-
каждым из этих предикатов. Нижеследующая программа соответствует этим
требованиям:
domains
лицо = symbol
смена = symbol
запрос = знает (лицо,лицо) ; работает (лицо, смена)
predicates
знает (лицо, лицо)
работает (лицо, смена)
один_раз (запрос)
clauses
работает (билл, дневная).
работает(нэнси, дневная).
знает (X,Y): -
работает(X, S), :
работает (Y, S),
i XOY.
один_раз(работает(А, В)) : —
работает(А, В), !.
один_раз (знает (С, Д)) :-
знает (С, Д), ! .
426 ПРИЛОЖЕНИЯ
Должно быть ясно, что данную реализацию предиката "один_раз"
нельзя использовать в других целях. Быть может, окажется возможным
написать какой-то препроцессор для Турбо Пролога, который будет ав-
автоматически преобразовывать общее определение метаязыкового пре-
предиката (вроде предиката "один_раз") в совокупность фраз, ориентиро-
ориентированных на решение конкретной задачи.
Подход к программированию на языке Пролог, излагаемый в данной
книге, требует, чтобы существовала возможность расширения обраба-
обрабатывающей структуры Пролога за счет написания процедур общего назна-
назначения (см. разд. 6.1 и 7.5). Вообще говоря, при работе с Турбо Прологом
невозможно пользоваться таким подходом.
V. ОТВЬГЫ К УПРАЖНЕНИЯМ
Ответы к упражнениям
Глава 1 -
3.
группа (генри, компиляторы).
группа (нэнси, компиляторы).
группа (сюзан, сети).
знает (ЛицоА, ЛицоБ) : —
группа (ЛицоА, Группа),
группа (ЛицоБ, Группа).
4. Отношение "знает" симметрично и имеет вид один-к-одному. С со-
социальной точки зрения отношение "знает" к тому же и нерефлексивно.
Приведенная выше программа, однако, является рефлексивной. Ее мож-
можно превратить в нерефлексивную путем добавления еще одной подцели,
в которой употребляется встроенный предикат "\ = = " (об этом предика-
предикате будет рассказано в гл. 3):
знает (ЛицоА, ЛицоБ) : —
группа (ЛицоА, Группа),
группа (ЛицоБ, Группа), {
ЛицоА \ = = ЛицоБ. 4
5. Вот еще один пример транзитивного отношения: f
% Элемент Изделие h
входит_в (конденсатор, дисковод). ;*"
входит _в (дисковод, компьютер). {
входит _в (компьютер, вычислительная-система). '.:"¦
% Изготовитель Изделие
изготавливает (sprague, конденсатор).
изготавливает (atasi, дисковод).
изготавливает (convergent, компьютер). ' *;
V. ОТВЕТЫ К УПРАЖНЕНИЯМ 427
изготавливает (' AT&T ', вычислительная—система).
% Поставщик Пользователь Изделие
поставляет (sprague, atasi, конденсатор).
поставляет (atasi, convergent, дисковод).
поставляет (convergent, 'AT&T', компьютер).
использует_изделия_от (Пользователь, Поставщик, Изделие) : —
поставляет (Поставщик, Пользователь, Изделие).
использует_изделия_от (Пользователь, Поставщик 1, Изделие) : —
поставляет (Поставщик2, Пользователь, —),
использует _изделия_от (Поставщик2, Поставщик 1, Изделие).
6. Правило "конкурент" должно быть симметричным и является
таковым. Однако, как и приведенное выше правило "знает", оно должно
быть не рефлексивным. Его можно превратить в нерефлексивное правило
точно таким же образом, как это было сделано с правилом "знает".
Глава 2
1.
! ?-XislO,YisX*3.
Х=10
Y=30
| ?- X is 10, YisX*3, Y is 300.
нет
При вычислении третьей подцели последнего запроса переменная Y
уже будет конкретизирована, поэтому данная подцель равнозначна провер-
проверке значения Y. В этом упражнении подчеркивается, что в Прологе отсут-
отсутствует деструктивное присваивание.
2.
площадь (Основание, Высота, Площадь) : —
Площадь is Основание * Высота.
! ?- площадьA0,2, П).
Л = 20
! ?-площадь A0, В, 20).
арифметическая ошибка
Данная программа не является обратимой.
4. Существует два простых решения. Первое из них по форме соответ-
соответствует процедуре "длина". Оно леворекурсивно и подсчитывает слова по
пути назад от конца списка.
% + +
найти—слово (Слово, [Слово I Список], Счетчик) : —
найти—слово (Слово, Список, СубСчетчик),
Счетчик is СубСчетчик + 1.
428 ПРИЛОЖЕНИЯ
найти_слово (Слово, [XСлово | Список], Счетчик) : —
найти_слово (Слово, Список, Счетчик).
найти—слово(_, [ ],0).
Второе решение является праворекурсивным. В нем используется до-
дополнительный аргумент, предназначенный для накопления суммы по мере
продвижения к концу списка. Когда будет достигнут конец списка, накоп-
накопленная сумма будет передана четвертому аргументу. (Это решение будет
более эффективным, чем предыдущее, доя тех версий Пролога, где осущест-
осуществляется оптимизация остаточной рекурсии; см. приложение IV.)
% + + + - ¦
найти-слово (Слово, [Слово ] Список], Накопитель, Счетчик) : —
НовНакопитель is Накопитель + 1,
найти—слово (Слово, Список, НовНакопитель, Счетчик).
найти_слово (Слово, [XСлово [ Список], Накопитель, Счетчик) .:—
найти_слово (Слово, Список, Накопитель, Счетчик).
найти_слово (—, [ ], Накопитель, Накопитель) .
% пример запроса:
! ?- найти_слово(the, [the, dog, in, the, barn], 0, C).
C = 2
5.
длина ([пусто ! R], Счетчик) :—
длина (R, Счетчик).
длина ([F ] R], Счетчик) :-
длина (R, ТекущСчетчик),
Счетчик is ТекущСчетчик + 1.
длина ([ ], 0).
6. Возможные ответы к этому упражнению рассматриваются в гл.4.
7.
всего([кл^_,Тариф, Дни) i Остаток], Итого) : —
всего (Остаток, ТекущСумма), j
< Итого is ТекущСумма + Тариф * Дни.
всего([ ],0).
8.
родитель (генри, джек).
родитель (джек, ричард).
родитель (ричард, чарльз).
родитель (чарльз, джейн).
npefl(X,Y,[X,Y]):- s
родитель (X, Y).
V. ОТВЕТЫ К УПРАЖНЕНИЯМ 429
пред(Х, Y, [X | Остаток]) :-
родитель (X,Z),
. пред (Z, Y, Остаток).
10.
% +
дд_в_список (дд (Имя, Отд, Долж, Окл, Предыдущ, Последующ),
%
ИтогСписок) :-
дд_в_список (Предыдущ, ПредыдСписок),
дд_в_список (Последующ, ПоследСписок),
присоединить (ПредыдСписок, [ел (Имя, Отд, Долж, Окл)!
ПоследСписок], ИтогСписок).
дд_в_список(епA, [ ]).
11. В процедуре "обр—печать" при унификации заголовков фраз вы-
выполняется сопоставление с эталоном, которое определяет условия при-
применения фраз. В процедуре "нпредок" нет сопоставления с эталоном
при унификации заголовков фраз, поэтому интерпретатор должен активи-
активировать тело фразы, чтобы определить, нужно ли использовать эту фразу.
Г л а в а 3
1.
! ?— путешествие (амтрак, нью_йорк,Х, _),!,
путешествие (амтрак, X, Y, _).
площадь (Основание, Высота, Площадь) :—
nonvar (Основание), nonvar (Высота),
Площадь is Основание * Высота.
площадь (Основание, Высота, Площадь) :—
nonvar (Основание), nonvar (Площадь),
Высота is Площадь / Основание.
площадь (Основание, Высота, Площадь) :—
nonvar (Высота), nonvar (Площадь),
Основание is Площадь / Высота.
Если два из трех аргументов не будут конкретизированы, то задачу все
равно можно решать, если воспользоваться процедурой, генерирующей це-
целые числа. См. процедуру "ген_чисел" из приложения III.
430 ПРИЛОЖЕНИЯ
3. Полное множество ответов должно состоять только лишь из ответов
мери и брайен. Запрос А полон и неэффективен. Запрос Б неполон и неэф-
неэффективен. Запрос В неполон и эффективен. Запрос Г и полон, и эффективен.
права (X) :-
шоферские_курсы (X),
возраст (X, 16).
права (X) :-
возраст (X, Возраст), Возраст > = 17.
4.
ньюйоркскийадрес (милфорд_плаза).
нью_йоркский_адрес(конфуциус_плаза).
связывает (А, Б, такси) :—
нью_йоркский_адрес(А),
нью_йоркский_адрес(Б), . - .
not (связывает (А, Б, автобус)),
not (связывает (А, Б, поезд)).
состояние (Машина, нормальное) :—
not (включен_аварийный_сигнал (Машина, Аварийныйсигнал)).
клиент (X, 'АТ&Т'):-
имеет_телефон ( X),
not (клиент (X, mci)),
not (клиент (X, sprint)).
5.
| ?- repeat,
write ('введите имя школьного товарища:'),
read (Имя),
( Имя = end % обход добавления факта
% "школьный_товарищ (end)".
»
assert (школьный_товарищ(Имя))
),
Имя = end,
\t
школьный_товарищ (Имя),
write (Имя), nl,
fail. • :¦¦
6. Первый способ: база данных является множеством фактов. .
сделка (смит, авиабилет, 139).
сделка (родригес, благотворительный_взнос, 25).
V. ОТВЕТЫ К УПРАЖНЕНИЯМ
431
текущ_сумма @).
% + -
сумма_сделки (Имя, Сумма) :—
сделка (Имя, _, Стоимость),
один_раз (retract (текучц_сумма (Текущ) ) ),
НовТекущ is Текущ + Стоимость,
assert (текущ_сумма(НовТекущ)),
fail.
сумма_сделки (Имя, Сумма) :—
retract (текущ_ сумма (Сумма) ),
assert (текущсумма @) ).
Второй способ: база данных является списком структур. Для удобства
проверки эгот список хранится в программе в виде факта "список".
список ([сд (смит, авиабилет, 139),
сд(родригес, благотворительный_взнос, 25)]).
% + ?
р_сумма_сделки([сд(Имя, _, Стоимость) ] Остаток], Имя, Сумма) :—
р_сумма_сделки(Остаток, Имя, ТекущСумма),
Сумма is ТекущСумма + Стоимость.
р_сумма_сделки([сд(ХИмя, _., Стоимость) J Остаток], Имя, Сумма) :—
ХИмя \==Имя,
р_сумма_сделки(Остаток, Имя, Сумма).
р_сумма_гделки([ ],_, 0).
] ?— список (L), р_сумма_сделки(L, смит, Итого).
Итого = 139
8.
список _путешествий (
[п(амтрак, нью_йорк,
п (ндж_транзит, нью_йорк,
п(амтрак,
п (грейхаунд,
п (амтрак,
п(пигшз,
п (пиплз,
бостон,
принстон,
портленд,
портленд,
Вашингтон,
Вашингтон,
нью_йорк,
бостон,
бостон,
нью_йорк,
нью_йорк,
бирлингтон,
можно_путешествовать(ГородА, ГородБ. Список) :-
элемент(п(_, ГородА, ГородБ, _), Список).
можно_путешествовать (ГородА, ГородБ, Список) :—
элемент(п(_, ГородА, ГородВ, _), Список),
можно_путешествовать(ГородВ, ГородБ, Список).
поезд),
поезд),
поезд),
автобус),
поезд),
самолет),
самолет) ]).
432 ПРИЛОЖЕНИЯ
! ?- список_путешествий (СП),
можно_путешествовать(нью_йорк, портленд, СП).
9.
% Многие Один
группаО (генри, компиляторы).
группаО(нэнси, компиляторы).
группаО(сюзан, сети).
группа (Имя, Группа) :-
nonvar (Имя),
группаО (Имя, Группа),!.
группа (Имя, Группа) :—
уаг(Имя),
группаО (Имя, Группа).
группа (Имя, Группа) : —
not (группаО (Имя, Группа)), . - .
( уаг(Имя), ' '
write ('имя?'),
read (Имя),
nonvar (Имя)
),
( var (Группа),
write ('группа?'),
read (Группа),
nonvar (Группа)
),
assert (группаО (Имя, Группа)).
11.
:-ор E00, xfy, —).
:-орD99, xfy, ->).
можно_путешествовать5 (А, Б, (А—Вид_тр- >Б)) :—
путешествие (_, А, Б, Вид_тр).
можно_путешествовать5 (А, Б, (А—Вид_тр- >Рпуть)) :-
путешествие (_, А, В, Вид_тр),
можно_путешествовать5 (В, Б, Рпуть).
Глава 4
1. Ниже приводятся новые версии базы данных и процедур, в которых
учитывается расстояние.
куинс,
бронкс,
куинс,
бронкс,
принстон.
принсгон,
жел_дорога,
автомобиль,
автобус,
метро
автомобиль,
автобус,
5).
25)
8).
4V
35)
50)
V. ОТВЕТЫ К УПРАЖНЕНИЯМ 433
% Из В Транспорт Мили
путешествие (манхэттен, ньюарк, автобус, IS),
путешествие (манхэттен,
путешествие (ньюарк,
путешествие (бронкс,
путешествие (манхэттен,
путешествие (ньюарк,
путешествие (манхэттен,
% Обеспечение симметрии запросов к базе данных
% "иутешествие/4"
сим_п> юшествис ^А, Б, Вид г,.», Мили) :—
путешествие (Л, Ь, Вьд_тр, Мили).
сим__пу]„а.оствие(л, Ь, вид_тр, Мили) :¦-
путешествие (Б, А, Вид_тр, Мили).
% + + + -
тснр_путешествоватьЗ(След, А, Б, Мили— м(Вид_тр, Б)) :— % A)
А \ == Б,
сим_путешествие (А, Б, Вид_тр, Мили).
тснр_нутешествоватьЗ(След, А, Б, Мили—м(Вид_тр1,В,Вид_тр2) :— % B)
А\==Б,
сим_путешествие(А, В, Вид_тр1, Мили1), % генерировать В
not (элемент(В, След)), % проверить В
тснр_путешествоватьЗ([В | След], В, Б, Мили2— Вид_тр2),
Мили is Мили1 + Мили2.
Рекурсивное решение:
р_наилучший_маршрут (А, Б, Маршрут) :-
findall (Вид_тр,
тснрпутешествоватьЗ ([ ], А, Б, Вид_тр),
Список),
keysort (Список, ОрсортСписок),
ОтсортСписок = [ Маршрут J _ ].
Решение, в котором используется поиск с возвратом:
оптимальный_маршрут(_, 100000).
наилучший_маршрут(А, Б, Маршрут) :—
тенр путешествоватьЗ([ ], А, Б, Мили—Маршрут),
один_раз (оптимальный_маршрут(ОптМаршрут, ОптМили)),
( Мили < ОптМили,
о дин_ раз (retra ct (оптимал ьный_маршрут (_,_))),
15. Дж. Малпас
434 ПРИЛОЖЕНИЯ
assert (оптимальный_маршрут (Маршрут, Мили))
»
Мили > а ОптМили
),
fail.
наилучший_марщрут(А, Б, Маршрут) :-
retract (оптимальный., маршрут (Маршрут, _)),
assert (оптимальный_ маршрут( , 100000)).
Если в Вашей версии Пролога достаточно эффективно реализован встроен-
встроенный предикат "keysort", то рекурсивная версия программы будет выпол-
выполняться более быстро. Версия программы в которой используется поиск с
возвратом, потребует меньшего объема памяти. Рекурсивное решение осно-
основывается на подходе к программе с позиций потока данных, а решение,
в котором используется поиск с возвратом, — на бихевиористическом
подходе. -
2. Нижеследующее правило "можно_занрашивать" охватывает случай,,
когда пункт отправления неизвестен:
% неизвестен пункт отправления:
можно_запрашивать(путешествие (А, Б, Вид_тр),
'введите пункт отправления:',
А):-
non var (Вид _тр), nonvar(B).
Далее приводится версия процедуры "найти_или_спросить", которая
может работать с любым количеством неизвестных аргументов. Вторым
аргументом факта "можно_запрашивать2" является список подсказок —
по одной на каждый аргумент факта "путешествие".
можно_запрашивать2(путешествие(Исх_пункт, Пункт_назнач, Вид_тр)
['откуда?', 'куда?', 'видтранспорта?']).
найти_или_спросить2Cапрос) :- Запрос.
найти_или_спросить2(Запрос) :—
notCanpoc), % это правило вступает в силу, если
% запрос терпит неудачу
можно _запрашивать2 (Запрос, СнисокПодсказок),
Запрос = .. [Пред ] СписокАрг],
проверить_каждый (СписокАрг, СписокПодсказок),
assert (Запрос).
проверить_каждый([Арг [ СписокАрг],
[Подсказка | СписокПодсказок]) : —
( var (Apr),
write (Подсказка),
V. ОТВЕТЫ К УПРАЖНЕНИЯМ 435
read (Apr)
nonvar (Apr)
).
!, проверить_каждый (СписокApr, СиисокПодсказок).
проверить_каждый ([ ],_).
Глава 5
1. Процедура "читатьпредлож" воспримет предложение, занимающее
более одной строчки. Если Вы наберете несколько предложений на одной
строчке, то будет воспринято лишь первое из них. Что произойдет с осталь-
остальными символами этой строчки, будет зависеть от вида буферизации вход-
входных данных в Вашей версии Пролога.
2. Форма записи предиката "вводстроки", вырабатывающего список
слов по строке входной информации, будет различной в разных версиях
Пролога. Ниже приводится простой вариант решения, предназначенный для
СиПролога. Недостатком этой программы является то, что она в качестве
последнего слова возвращает символ перехода к новой строке.
%
вводстроки( [W ] Lw]) :— % считать строку
getO(C),
читатьслово (С, W, C1),
остатокпредл (W, Cl, Lw), !.
% предыдущее слово и следующий символ введены;
% считать оставшуюся часть строки.
% + + -
остатокпредл (W, __, [ ]):-
границапредл (W), !. % конец, если предыдущим словом
% была граница предложения,
остатокпредл(W, С, [Wl] Lw]) :-
читатьслово (С, Wl, C1),
остатокпредл (Wl, Cl, Lw).
% взять первый символ, прочитать слово, вернуть следующий
% символ.
% +- -
читатьслово (С, W, __) : —
нереводстроки (С),
name(W, [С]). % построить слово по символам,
% содержащимся в списке С.
12*
436 ПРИЛОЖЕНИЯ
читатьслово (С, W, C1) :-
пунктуация(С),
name(W, [С]), % построить слово по символам,
% содержащимся в списке С.
getO(Cl).
читатьслово (С, W, C1): —
допустимый_символ (С),
i
get(XC2),
остатокслова (С2, Lc, С1), 7с ввести последующие
% символы.
name(W. [С |Lc]). 7r построить слово,
читатьслово (С, W, C1): -
getO(C2). % символ "С" неприемлем, ввести новый
7с СИМВОЛ. -
читатьслово (С 2, W, C1). % попытаться снова.
7с составлять слово из символов до тех пор, пока не
7с встретится недопустимый символ
7с + -
остатокслова (С, [С | Lc], С1):- % объединить символы в список
допустимый_символ (С),
getO(C2),
остатокслова (С2, LC, C1).
остатокслова (С, [ ], С). % конец слова, если символ С
% недопустим
7с символы, считающиеся самостоятельными словами:
пунктуацияD4). %,
пунктуация E9). %;
пунктуацияE8). %:
пунктуация F3). %?
пунктуация C3). % !
пунктуацияD6). % .
аереводстроки A0). % символ перевода строки для ОС
% UNIX, VMS и т.д.
7с диапазоны кодов допустимых символов:
допустимый символ (I) : —
допустимый_символ (I) :—
допустимый_символ (I) : —
1>96,
1>64,
1>47,
1<
1<
1<
С 123.
С 91.
С 58.
% a-z
%A~z
% 0—9
V. ОТВЕТЫ К УПРАЖНЕНИЯМ 437
% символы, заканчивающие строку:
границапредл ('
'). ?t перевод строки
Данн>ю задачу можно бьшо бы решить более просто, если написать вариант
процедуры "вводполя/1" (см. разд. 3.9), которая возвращала бы список
всех символов строки, и другую процедуру, которая разбивала бы этот
список на отдельные слова.
6. Символы ( и ) следует объявить как знаки пунктуации. Если симво-
символы : и — объявлены как допустимые, то процедура "читатьпредлож" вы-
выдаст сочетание символов :— как отдельное слово, если только сразу после
этого сочетания располагается пробел или символ перевода строки.
8. Довольно трудно добавить команду "суммировать" без серьезной
переделки программы. Лучше всего будет связать эту команду с заключи-
заключительным действием, выполняемым при обработке запроса. Так, команда
"отобразить" должна приводить к тому, что заключительным действием
будет обращение к процедуре "печатать_тсписок" (это сейчас выполняется
по умолчанию). Команда "суммировать" должна приводить к тому, что
заключительным действием будет вызов новой программы, названной, к
примеру, "суммировать_тсписок". Эта программа должна суммировать
все значения, передаваемые ей через аргумент ((Printlist)), и печатать ито-
итоговую сумму.
Глава 6
1. Отношение "является" можно гарантировано превратить в транзитив-
транзитивное, если задать явную базу данных "являетсяО" и написать рекурсивную
процедуру "является", которая обращается к. базе данных "являетсяО":
являетсяО (канарейка, птица).
являетсяО(твити, канарейка).
является (X, Y):-
являетсяО (X, Y).
является (X, Y) :—
являетсяО (X, Z),
является (Z, Y).
Однако отношения "летает" и "цвет" сами являются транзитивными (ре-
(рекурсивными), причем это их свойство зависит от отношения "является".
Для того чтобы предотвратить бесконечную рекурсию при обработке
запросов к этим процедурам, нужно заменить подцель "является" в теле
каждого рекурсивного правила на подцель "являетсяО":
летает(птица).
летает(Х) :— являетсяО(X, Y), летает(Y).
438 ПРИЛОЖЕНИЯ
цвет (канарейка, желтый).
цвет(Х, Y): - являетсяО(Х, Z), цвет^, Y).
2.
являетсяО(квадрат, прямоугольник).
являетсяО(прямоугольник, параллелограмм).
свойство (параллелограмм,
'площадь равна произведению основания на высоту'),
свойство (прямоугольник,
'все углы равны 90 градусам'),
свойство (квадрат, 'все стороны равны'),
свойство (Узел, Свойство) :—
являетсяО (Узел, ДругойУзел),
свойство (ДругойУзел, Свойство).
подсчет (Состояние, Счетчик) :-
% ввести критерий выбора:
послать (Состояние, за (тип, Т)),
послать (Состояние, за (марка, М)),
послать (Состояние, за (вес, В)),
послать (Состояние, за (поверхность, П)),
послать (Состояние, за (цвет, Ц)),
I
% подсчитать количество целостных информационных
% элементов, удовлетворяющих критериям выбора:
findall (Т, вед_бум(бумага, Т, М, В, П, Ц), Список),
длина (Список, Счетчик).
Примечание: при обращении к встроенному предикату "findall" не имеет
никакого значения, какие сведения фактически собираются в список
"Список", так как нас интересует лишь количество элементов списка,
а не его содержание.
Гл ав а 7
1. Пример базы данных с циклическими данными:
путешествие(амтрак, нью Йорк, бостон, поезд),
путешествие(грейхаунд, бостон, нью_йорк, автобус).
Обычный интерпретатор, выполняя нижеследующий запрос к процедуре
"можно_пугешествовать4":
| ?— можно_путешествовать4(нью_йорк, X).
V. ОТВЕТЫ К УПРАЖНЕНИЯМ 439
будет вырабатывать ответы по такой схеме:
X = бостон ;
X = ньюйорк ;
X = бостон ;
X = нью_йорк ;
Ксли данный запрос выполнять при помощи процедуры "иоц", то будут
получены точно такие же ответы. Процедура "иоц" обнаруживает только re
циклы, в которых одна и та же подцель попадается три раза подряд. Приве-
Приведенный выше запрос входит в осциллирующий цикл, который интерпретатор
"иоц" не сможет обнаружить. Наилучшее решение проблемы осцилляции бы-
было предложено в процедуре "тенрпу тешествоватьЗ" из гл. 4. Можете ли
Вы написать универсальную программу-решатель задач, которая будет об-
обнаруживать осциллирующие множества ответов, используя ту же методику,
какая была применена в процедуре "тенр—путешествоватьЗ"?
2. Ввиду того что успешный вызов процедуры "поместить" фактически
приводит к переходу из одного состояния в другое-, смысл датк. го вызова
станет более ясным, если имена нужных состояний будут фигурировать в
качестве аргументов этой процедуры, например:
% + + ?
поместить (Объект, Куда_поместить, ТекущСост, НовСост) :—
3.
% объявить свойство один-к-многим отношения "мать"
% Отношение Один Много
один_ много (мать (Мать, Ребенок), Мать, Ребенок).
% объявить свойство один-к-одному отношения
% "соц_страх_номер":
% Отношение Один Один
один_один (соц_ страх_номер (Имя, Номер), Имя, Номер).
% решатель задач, которому известно про отношения
% один-к-одному и один-к-многим:
ps(true):— !.
рз ((А, Б) ) :— % составной запрос
рз(А),
рз(Б).
рз(А) :— % особый случай: А— это отношение вида
% один-к-многим
440 - ПРИЛОЖЕНИЯ
один_много(А, X, Y),
I
ом_рз(А, X, Y). '
pi (А) :- % особый случай : А - это отношение вида
% один-к-одному
один один (А, X, Y),
оо_рз(А,Х, Y).
рз(А) :- % отношение А не является ни отношением
% вида один-к-сдному, ни отношением вида -
% один-к-многим -
clause(A, Тело),
рз(Тело).
% эффективно обработать отношение вида один-к-многим:
% Один Много . -
ом_рз(А, X, Y) :-
nonvar(Y),
clause (А, Тело),
рз(Тело), !.
ом_рз(А,Х, Y) :-
var(Y),
clause(A, Тело),
рз(Тело).
% эффективно вычислить отношение вида одан-к-одному:
%. Один Один
оо_рэ(А, X, Y):-
clause(A, Тело),
рз(Тело), !.
Отношения вида многие-кодному можно реализовать, объявив их как
отношения вида "один_много" и изменив порядок следования аргументов
на обратный.
ДОПОЛНЕНИЕ
1. Встроенные предикаты,
предназначенные для работы с окнами
clearwindow/O — очистка текущего окна
Данный предикат очищает текущее текстовое окно, заполняя
его фоновым цветом. Курсор устанавливается в точку с координа-
координатами @, 0).
colorsetup/1 — изменение цветов в текущем окне
Данный предикат дает возможность пользователю интерактив-
интерактивно изменять цвет текущего окна — по аналогии со средой Турбо-
Пролога. Если параметр предиката имеет значение 0, то можно
менять цвета самого окна, а если этот параметр имеет значение 1,
то можно менять цвета рамки.
cursor/2 — установка курсора в заданное положение в текущем
окне либо считывание координат текущего положения курсора
Первый аргумент данного предиката обозначает номер строки,
а второй — номер столбца. Если аргументы являются входными,
то курсор ставится в текущем окне в точку с указанными коор-
координатами. Если аргументы являются выходными, то их значения
после вызова данного предиката будут соответствовать текущим
координатам курсора.
cursorform/2 — установка формы курсора или выдача инфор-
информации о форме курсора
Первый аргумент обозначает начальную строку развертки сим-
символа (матрица точек, которой отображается любой символ, состоит,
как правило, из восьми строк развертки), а второй аргумент —
конечную строку развертки. Данный предикат позволяет изменять
высоту отображаемого курсора и положение его в матрице точек,
служащей для отображения символов. Ширина курсора остается
неизменной.
existwindow/1 — проверка, существует ли окно с заданным
номером
442 ДОПОЛШ'НИЕ
Аргументом является номер окна. Предикат терпит неудачу,
если окна с таким номером не существует.
framewindow/1 изменение атрибутов рамки окна
Аргумент предиката позволяет изменять атрибуты рамки окна,
список применимых атрибутов приводится в "Руководстве поль-
пользователя по Турбо Прологу".
framewindow/4 - изменение атрибутов и символов рамки
окна
Все четыре аргумента являются входными. Первый аргумент
позволяет установить цвет рамки окна. Второй аргумент содержит
текст, который будет высвечиваться в составе верхней линии рам-
рамки. Третий аргумент указывает, где (в пределах перхней границы
рамки) должен размешаться заголовок окна - i» середине или
с определенной позиции рамки. Четвертый аргумент представляет
собой строку из шести символов - из этих символов будут
строиться, соответственно, верхний левый угол рамки окна, пра-
правый верхний угол, нижний левый угол, правый нижний угол, гори-
горизонтальная линия, вертикальная линия.
gotowindow/1 — быстрый переход от одного окна к другому
Аргументом предиката является номер окна, которое будет
сделано активным. Содержимое старого окна не будет запоми-
запоминаться в оконном буфере.
makewindow/8 -- создание на экране дисплея новою окна,
параметры рамки которого выбираются по умогиянню
Если все аргументы предикатч являются входными, го создает-
создается новое окно. Если же все аргументы являются рылиднымк, то
через иих выдаются значения параметров тскущо?о окна. Первый
аргумент — номер окна, второй аргумент ~ атрибут экрана, третий
аргумент — атрибут рамки (если эю значение но равно нулю, то
по границе окна строится рамка), четвертый аргумент - текст,
выводимый в верхней границе рамки (если задаете* пустая строка,
то никакого текста выводиться не будет), пятый аргумент — номер
строки экрана, гце должен располагаться левый верхний угол окна,
шестой аргумент — номер столбца, где должен располагаться Левый
верхний угол окна, седьмой аргумент — высота окна в строках,
восьмой аргумент — ширина окна в столбцах.
makewindow/11 - создание на экране дисплея нового окна,
параметры рамки которого задаются пользователем
Если все аргументы являются входными, то создается новое
окно. Если же все аргументы являются выходными, то через них
ДОПОЛНЕНИЕ 443
выдаются значения параметров текущего окна. Первые восемь
аргументов — точно такие же, как у предиката makewindow/8.
Девятый аргумент — признак очистки окна @ - не нужно очищать
окно, 1 - очистить окно), десятый аргумент - указатель разме-
размещения заголовка окна, располагающегося на верхней границе рамки
A — необходимо центрировать заголовок, 0 — поместить заголовок,
начиная с заданного столбца), одиннадцатый параметр - строка
из шести символов, которыми, соответственно, будут строиться
верхний левый угол рамки, верхний правый угол, нижний левый
угол, нижний правый угол, горизонтальная линия, вертикальная
линия.
removewindow/O — удалит1 текуш™ окно
Текущее окно удаляется с экрана, а его место занимают окна,
находившиеся под ним.
removewindow/2 — удалить заданное окно
Первый.аргумент задает номер окна. Второй аргумент — признак
необходимости обновления содержимого окон, находившихся
под удаляемым окном @ — не обновлять, 1 - обновлять).
resizewindow/O - вызов стандартной процедуры изменения
размеров текущего окна
вызывается процедура изменения размеров окна, с помощью
которой вы можете изменить размер окна точно таким же образом,
как и в среде Турбо-Пролога.
re^izewindow/4 -- изменить местоположение и размер теку-
текущего окна
Даииьтй предикат позволяет изменить размер, местоположение
или то и другое вместе для текущего окна. Первый аргумент -
новая начальная строка окна, второй аргумент — размер окна в
строках, третий аргумент — новый начальный столбец окна, чет-
четвертый аргумент — размер окна в столбцах.
scr_attr/3 — установка или выдача атрибутов экрана
Два первых аргумента всегда должны быть входными. Они
задают координаты знакоместа на экране (строка и столбец). Если
третий аргумент будет входным, то он задает атрибут символа,
располагающегося в этом месте экрана. Если же третий аргумент
будет выходным, то в него запишется значение атрибута символа
в данной позиции экрана.
scr_char/3 — запись/считывание символа на экран/ с экрана
444 . ДОПОЛНЕНИЕ
Первые два аргумента являются входными, они задают коорди-
координаты (строка, столбец) символа на экране дисплея. Третий аргу-
аргумент — считываемый или записываемый символ (этот аргумент,
соответственно, будет выходным или входным).
scroll/2 — прокрутка содержимого текущего окна
Содержимое текущего окна будет смещено на число строк
(первый аргумент) и столбцов (второй аргумент), задаваемое
в виде аргументов данного предиката. Положительное значение
первого аргумента означает смещение вверх, отрицательное — вниз.
Положительное значение второго аргумента означает, смещение
содержимого окна влево, отрицательное — вправо.
shiftwindow/1 -- перемещение к новому активному окну или
выдача номера текущего активного окна
Аргументом данного предиката является номер окна. Если-
аргумент — входной, то происходит переход к новому окну. При.
этом запоминаются содержимое текщуего активного окна и по-
положение курсора в нем. Если аргумент - выходной, то через него
выдается номер текущего активного окна.
window_attr/l — установка атрибутов активного окна
Входной аргумент данного предиката задает атрибуты теку-
текущего окна.
window—str/1 — чтение/запись строки из активного окна/в
активное окно
Если аргумент данного предиката является выходным, то в
строковую переменную считывается текст, отображаемый в настоя-
настоящее время в активном окне — следовательно в этой переменной
будет столько же строчек текста, как и в активном окне. Если же
аргумент предиката является входным, то в активное окно выво-
выводится содержимое строки. При этом если в такой строке будет
содержаться больше строчек текста, чем строчек в окне, то будет
выведено в окно столько символов, сколько может Поместиться
в окне.
2. Перечень встроенных предикатов,
предназначенных для работы
с графическим интерфейсом фирмы Борланд (BGI)
агс/5 — вычерчивание дуги окружности
bar3d/6 - вычерчивание трехмерного столбика для построения
диаграмм
circle/6 - вычерчивание окружности заданного радиуса с цент-
центром в указанных координатах
ДОПОЛНЕНИЕ **5
cleardevice/3 - очистка графического экрана
clearviewport/O - очистка текущего видеопорта
closegraph/O — прекращение работы графической системы
detectgraph/2 — определение типа драйвера дисплея и режима
его работы путем проверки используемых аппаратных средств ПЭВМ
drawpoly/1 — вычерчивание многоугольника
ellipse/6 — вычерчивание дуги эллипса
fillellipse/4 — вычерчивание эллипса и закраска его с заданными
текстурой и цветом заполнения
fillpoly/4 - вычерчивание многоугольника и закраска его с
заданными текстурой и цветом заполнения
floodfill/3 — закраска оконтуренной области с заданными тек-
текстурой и цветом заполнения
getarccoords/6 — выдача координат, использованных при послед-
последнем вызове предиката
getaspectratio/* — вывод текущего масштабного множителя,
используемого для недеформированного вывода графических
изображений
getbkcolor/1 — выдача текущего цвета фона
getcolor/1 — выдача текущего цвета, которым выполняется
вычерчивание изображений
getdefaultpalette/1 — выдача текущей цветовой палитры
getdrivername/1 — выдача имени текущего графического драй-
драйвера
getfillpattern/1 — выдача задаваемой пользователем текстуры
закраски изображения
getfillsettings/2 — выдача информации о текущих цвете и тек-
текстуре закраски изображения
getgraphmode/1 — выдача текущего графического режима
getimage/5 — запоминание битового изображения заданной
области экрана
getlinesettings/3 — выдача информации о текущих толщине
и стиле вычерчиваемых линий
getmaxcolor/1 - выдача максимально допустимого значения
кода цвета элемента изображения (пикселя)
getmaxx/1 — выдача максимально допустимой координаты
Экрана по горизонтали
getmaxy/1 - выдача максимально допустимой координаты
экрана по вертикали
getmodename/2 - выдача названия графического режима
getmoderange/З — выдача диапазона кодов режимов для задан-
заданного графического драйвера
446 ДОПОЛНЕНИЕ
getpalette/1 - выдача информации о текущей цветовой палитре
getpalettsize/1 — выдача размера таблицы просмотра цветовой
палитры
getpixel/З - выдача цвета заданного элемента изображения
(пикселя)
get.textsettings/5 — выдача информации о текущем графичес-
графическом буквенном шрифте
getviewsettings/5 - выдача информации о текущем видеопорте
get.v/1 — выдача к.'оря^инаты х текущего положения курсора
get_v/l - выдача координаты у текущего положения курсора
graphdefaults/O — присваивание всем графическим параметрам
значений, принимаемых по умолчанию
images ize/5 - выдача объема намяги в байтах, требуемого для
запоминания заданного побитового изображения
initgraph/5 — инициализация графической системы
iine/4 — вычерчивание линии, соединяющей две заданные точки
!inerel/2 — вычерчивание линии, проходящей от текущей точки
до точки, для которой задается относительное смещение
linetn/2 - вычерчивание линии от текущей точки до заданной
moverel/2 — перемещение текущей i-очки на расстояние, зада-
задаваемое в относительных координатах
moveto/2 — перемещение из текущей точки в заданную
outtext/1 - вывод строки в видеонорт
outtextxy/З - вывод строки в заданном месте экрана
р^slice/5 - вычеркивание и закраска круговой секторной
диаграммы
pieslicexy/6 - вычерчивание и закраска эллиптической сек-
секторной диаграммы
putimage/4 — вывод побитового изображения на экран
putpixel/З - вывод пикселя в заданной точке
rectangle/4 — вычерчивание прямоугольника
restorecrtmode/O - восстановление экранного режима, сущест-
существовавшего до вызова предиката initgraph
setactivepage/1 — установка активной страницы для графичес-
графического вывода
setpalette/1 —изменение цветов палитры
setaspectratio/2 -¦ изменение принятого по умолчанию кор-
корректирующего коэффициента, обеспечивающего вывод на экран
неиекчженных изображений
setbkcolor/1 - установка цвета фона
setcolor/1 — установка текущего цвета вычерчиваемого изо-
изображения
ДОПОЛНЕНИЕ 447
setfillpattern/2 - выбор устанавливаемой пользователем тек-
текстуры закраски ичображеиия
setfillstyle/2 - установка цвета-и текстуры заполнения изо-
изображения
setgraphmode/1 — установка заданного графического режима
setpalette/2 - изменение одного из цветов палитры
settextjustify/2 - установка вида выравнивания текста
settextstyle/З - установка текущих характеристик текста
setusercharsize/4 - увеличение/уменьшение размеров шрифтов
setviewport/5 — установка параметров текущего видеопорта
для.графического вывода
setvisuatpage/1 - установка номера выводимой на экран гра-
графической страницы
setwriteniode/1 - установка режима вывода для вычерчивания
линий
textheight/2 — выдача высоты строки в пикселях
texttnode/2 -¦ установка иди считывание фактического коли-
количество строк или столбцов на экране
textwidth/2 выдача ширины строки в пикселях
СПИСОК ЛИТЕРАТУРЫ
1 Aho. А. V., and Ullman, J. D. [1979]. Principles of Compiler
Design, Addison-Wesley, Reading, Ma.
2 Aho, A. V., Hopcroft, J. E., and Ullman, J. D. [1983]. Data Struc-
Structures and Algorithms, Addison-Wesley, Reading, Ma.
3 Apt, K. R., and van Emden, M. H. [1982]. "Contributions to the
Theory of Logic Programming," Journal of the ACM 29:3
4 Bobrow, D. G. [1984]. "If Prolog is ihe Answer, What is the Ques-
Question?," Proc. International Conference on Fifth Generation
Computer Systems, Tokyo, Japan, November 6-9. Institute for
New Generation Computer Technology, pp. 138-148
5 Bowen, D., Znidarsic, D., ei al. [1985]. Quintus Prolog Reference
Manual, Quintus Computer Systems, Palo Alto, Ca.
Б Bowen, К A., and Kowalski, R. A. [1982]. "Amalgamating Langu-
Language and Metalanguage in Logic Programming," in Logic Pro-
Programming (K. L. Clark and S. A. Tarnlund, eds). Academic
, Press, London, pp. 153-172
7 Bowen, K. A., and Weinberg, T. [1985]. "A Meta-Lcvcl Extension of
Prolog," Proc. Symposium on Logic Programming, Boston,
Ma., July 15-18. IEEE Computer Society Press, New York, pp.
48-53
8 Воуег, С. В. [I968J. A History of Mathematics, Princeton Univer-
University Press, Princeton, N. J.
9 Brachman, R. J., Fikes, R. E., and Levesque, H. J. [1983]. "Kryp-
"Krypton: A Functional Approach to Knowledge Representation,"
Computer 16:10, pp. 67-74.
СПИСОК ЛИТЕРАТУРЫ 44*
tO Brachman, R. J. [1983]. "What IS-A Is and Isn't: An Analysis of
Taxonomic Links in Semantic Networks," Computer 16:10, pp.
30-36.
11 Brough, D. R., and Walker, A. [1984). "Some Practical Properties of
Logic Programming Interpreters," Proc. International Cm
ference on Fifth Generation Computer Systems, Tokyo, Jap»*,
November 6-9. Institute for New Generation Computer Tech-
Technology, pp. 149-158
12 Bundy, A. [I983J. The Computer Modelling of Mathematical
Reasoning, Academic Press. London
13 Bundy, A., and Welham, B. [1981]. "Using Meta-level Inference for
Selective Application of Multiple Rewrite Rules in Algebraic
Manipulation," Artificial Intelligence 16:2
14 Campbell, J. A. [1984). Implementations of Prolog, Ellis Horwood,
Chichester, England
15 Chang, C, and Lee, R. С [1973]. Symbolic Logic and Mechanical
Theorem Proving, Academic Press, New York
16 Chikayama, T. [1983]. "ESP—Extended Self-contained Prolog—as
a Preliminary Kernel of Fifth Generation Computers," New
Generation Computing 1:1. pp. 11-24
17 Clark, K. L. [1978]. "Negation as Failure," in Logic and Data Bases,
(H. Gallaire and J. Minker, eds.), Plenum Press, New York,
pp. 293-324
18 Clark, K. L., and Gregory, S. [1985]. "Notes on the Implementation
of Parlog," Journal of Logic Programming 2:1, pp. 17-42
13 Clark, K. L., McCabe, F. G., and Gregory, S. [1982]. "IC-PROLOG
Language Features," in Logic Programming, (K. L. Clark and
S. A. Tarnlund, eds), Academic Press, London, pp. 253-266
20 Clark, K. L, and McCabe, F. G. [1984]. micro-PROLOG; Program-
Programming in Logic, Prentice-Hall, Englewood Cliffs, N. J.
21 Clark, K. L, and Tarnlund, S. A. (eds.) [1982]. Logic Program-
Programming, Academic Press, London
450 СПИСОК ЛИТЕРАТУРЫ
22 Clocksin, W. F., and Mellish. С S. [1984]. Programming in Prolog,
Springer-Verlag, Berlin
23 Coelho, H., Cotta, J. C, and Pereira, L. M. [1982]. How to Solve it
with Prolog, Laboratio Nacional de Engenharia Civil, Lisbon
24 Colmerauer, A. A978]. "Metamorphosis Grammars," in Natural
Language Communication with Computers (L. Bole, ed.),
Springer-Verlag, Berlin, pp. 133-189
ZS Colmerauer, A. [1985]. "Prolog in 10 Figures," Communications of
the ACM 2i:\2, pp. 1296-1310
Z6 Copi, I. M. [1986]. Introduction to Logic, Macmillan, New York
27 Cory, H. Т., Hammond, P., Kowalski, R. A., Kriwaczek, F., Sadri,
F., and Sergot, M. J. [1984]. "The British Nationality Act as a
Logic Program," Logic Programming Research Reports,
Department of Computer Science, Imperial College, London,
England
28 Dahl, V., and Abramson, H. [1984]. "On Gapping Grammars," Proc.
Second International Logic Programming Conference, Uppsala,
Sweden, July 2-6. Ord and Form, pp. 77-88
29 Darvas, Г [1980]. "Logic Programming in Chemical Information
Handling and Drug Design," Proc. tx>gic Programming
Workshop, July 14, p. 261
30 Davis, M. [1983]. The Prehistory and Early History of Automated
Deduction," in Automation of Reasoning I (J. Siekmann and
G. Wrightson, eds.), Springer-Verlag, Berlin
31 Davis, R. E. [1982]. "Runnable Specification as a Design Tool," in
Logic Programming (K. L. Clark and S. A. Tarnlund, eds.),
Academic Press, London, pp. 141-152
32 Ennals. J. R. [1984]. Beginning Micro-PROLOG, Ellis Horwood,
Chichester, England
33 Gallaire, H., Minker, J., and Nicolas, J. M. [1978]. "An Overview
and Introduction to Logic and Data Bases," in Logic and Data
Bases (H. Gallaire and J. Minker, eds.), Plenum Press, New
York, pp. 3-32
СПИСОК ЛИТЕРАТУРЫ 451
34 Gazdar, G., Klein, E., Pullum, G. K., and Sag, 1. A. [1985]. Gen-
Generalized Phrase Structure Grammar, Harvard University Press,
Cambridge, Ma.
55" Goldberg, A., and Robson, D. [1983]. Smalltalk-80 The Language
and its Implementation, Addison-Wesley, Reading, Ma.
36 Goldstein, i. P., and Roberts, R. B. [1979]. "Nudge, a Knowledge-
based Scheduling Program," in Frame Conceptions and Text
Understanding (D. Metzing, ed.), de Gruyter, Berlin, pp. 26-45
37 Hamilton, A. G. [1978]. Logic for Mathematicians, Cambridge
University Press, Cambridge, England
38 Hammond, P., and Sergot, M. [1984]. apes: Augmented Prolog for
Expert Systems Reference Manual, Logic Based Systems
Richmond, Surrey, England
39 Hayes, P. J. A977). "In Defence of Logic," Proc. 1JCA1-77, MIT,
Cambridge, Ma., August 22-25. International Joint Confer-
Conferences on Artificial Intelligence, pp. 559-565
40 Hayes, P. J. [1979]. "The Logic of Frames," in Frame Conceptions
and Text Understanding (D. Metzing, ed.), pp. 46-60
41 Hayes, P. J. [1985]. "The Second Naive Physics Manifesto," in
Readings in Knowledge Representation (R. Brachman and H.
Levesque, eds.), Morgan Kaufmann, Los Altos, Ca., pp. 467-
486
42 Hayes-Roth, F., Waterman, D. A., and Lenat, D. B. (eds.) [1983^
Building Expert Systems, Addison-Wesley, Reading, Ma.
43 Hermes, H., and Markwald, W. [1974]. "Foundations of Mathemat-
Mathematics," in Fundamentals of Mathematics (H. Behnke, F. Bach-
mann, K. Fladt, and W. Suss, eds.), MIT Press, Cambridge,
Ma., pp. 1-88
44 Hilbert, D. [1904]. "On the Foundations of Logic and Arithmetic,"
in Front Frege to Godel, van Heijenoort (ed.), Harvard Univer-
University Press, Cambridge, Ma.
4ff Hodges, W. [1977]. Logic, Penguin, New York
46 Hogger, C. J. [1984]. Introduction to Logic Programming,
Academic Press, London
452 СПИСОК ЛИТЕРАТУРЫ
47 Horn, R. Е. [1983]. "An Overview of Trialectics with Applications to
Psychology and Public Policy," in Trialectics Toward a Practi-
Practical Logic of Unity (R. E. Horn ed.), Information Resources,
Lexington, Ma., pp. I -39
48 Kahn, К M., and Carlsson, M. [1984]. "How to Implement Prolog
on a Lisp Machine," in Implementations of Prolog (J. A.
Campbell, ed.), pp. 117-134
49 Kaplan, R. M., and Bresnan, J. [1984]. "Lexical-Function Grammar:
A Formal System for Grammatical Representation," in The
Mental Representation of Grammatical Relations (J. Bresnan.
ed), MIT Press, Cambridge, Ma., pp. 173-281
50 Kawanobe, K. [1984]. "Current Status and Future Plans of the Fifth
Generation Computer Systems Project," Proc. International
Conference on Fifth Generation Computer Systems, Tokyo, Ja^
pan, November 6-9. Institute for New Generation Computer
Technology, pp. 3-17
51 Kay, M. [1985]. "Parsing in Functional Unification Grammar," in
Studies in Natural Language Processing, Cambridge Univer-
University Press, Cambridge, England
52 Kitakami, H., Kunifuji. S., Miyachi, Т., and Furukawa, K. [1984].
"A Methodology for Implementation of a Knowledge Acquisi-
Acquisition System," Proc. International Symposium on Logic Pro-
Programming, Atlantic City, N. J., February 6-9. IEEE Computer
Society Press, New York, pp. 131-143
53 Kluzniak, F., and Szpakowisz, S. [1985]. Prolog for Programmers,
Academic Press, London
54 Kowalski, R. A. [1974]. "Predicate Logic as a Programming Langu-
Language," Proc. IFIP-74, North Holland, Amsterdam, pp. 569-574
55 Kowalski, R. A. [1979a]. Logic for Problem So/v/n^Elsevier-North
Holland, New York
56 Kowalski, R. A. [1979b]. "Algorithm - Logic + Control," Comm. of
the ACM 22, pp. 424-431
57 Kowalski, R. A., and Kuehner, D. G. [1971]. "Linear Resolution
with Selection Function," Artificial Intelligence 2, pp. 227-260
58 Kowalski, R. A., et al. [1984]. Fifth Generation Software, Course
Outline, Programming Logic Systems, Milford, Ct.
СПИСОК ЛИТЕРАТУРЫ 453
59 Kriwaczek, F. [198?]. "Some Applications of PROLOG to Decision
Support Systems," MSc Thesis, Imperial College, London
BO Kriwaczek, F. [1984]. "A Critical Path Analysis Program," in
micro-PROLOG: Programming in Logic (K. L. Clark and F.
G. McCabe). PP- 277-293
61 Li, D. [1984]. A PROLOG Database System, Research Studies
Press, Letchworth, England
62 Lloyd, J. W. [1984]. Foundations of Logic Programs, Springer-
Verlag, New York
63 Loveland, D. W. [1968]. "Mechanical Theorem Proving by Model
Elimination," Journal of the ACM 15:2
64 Manna, Z. and Wladinger, R. [1985]. The Logical Basis of Com-
Computer Programming, Addison-Wesley, Reading, Ma.
65 Matsumoto, Y., Kiyono, M., and Tanaka, H. [1984] "Facilities of
" the BUP Parsing System," Proc. Natural Language
Understanding and Logic Programming, Rennes, France, Sep-
September 18-20, pp. 71-80
66 McCabe, F. G., and Clark, K. L. [1985]. micro-PROLOG 5.2 Pro-
Programmers Reference Manual, Logic Programming Associates,
London, England
57 McCarthy, J., and Hayes, P. J. [1969]. "Some Philosophical Prob-
Problems from the Standpoint of Artificial Intelligence," in Machine
Intelligence 4 (B. Meltzer and D. Mitchie, eds.), Edinburgh
University Press, Edinburgh, pp. 463-502
68 McCord, M. С [1982]. "Using Slots and Modifiers in Logic Gram-
Grammars for Natural Language," Artificial Intelligence 18, pp.
327-367
69 McCord, M. С [1985]. "Modular Logic Grammars," Proc. 23rd An-
Annual Meeting of the Association for Computational Linguis-
Linguistics, Chicago, II., July 8-12, pp. 104-117
70 McDermott, D. [1983]. "DUC: A Lisp-Based Deduetive System,"
Technical Report, Department of Computer Science, Yale
University
71 Mendelson, E. [1979]. Introduction to Mathematical Logic, D. Van
Nostrand, New York
454 СПИСОК ЛИТЕРАТУРЫ
72 Minsky, М. [1979]. "A Framework for Representing Knowledge," in
Frame Conceptions and Text Understanding (D, Met/ing, ed.),
pp. 1-25
73 Miyachi. Т., Kunifuji, S.. Kitakami, K.. Furukawa. K., Takeuchi, A.,
and Yokota, H. [19841. "A Knowledge Assimilation Method
for Logic Databases," Proc. International Symposium on Logic
Programming, Atlantic City, N. J., February 6-9. IEEE Com-
Computer Society Press, New York, pp. 118-125
74 Moto-oka, T. et al. [1981]. "Challenge for Knowledge Information
Processing Systems." in Fifth Generation Computer Systems
(T. Moto-oka, ed). pp. 3-92
75 Nagel, E., and Newman, J. R. [1964]. Godel's Proof, New York
University Press, New York
76 Naish, L. 11985]. "All Solutions Predicates in Prolog," Proc. Sympo-
Symposium on Logic Programming, Boston, Ma., July 15-18. IEEE
Computer Society Press, New York, pp. 73-77
77 Nakashima, H. [1984]. "Knowledge Representation in Prolog/KR,"
Proc. International Symposium on Logic Programming, Atlan-
Atlantic City, N. J., February 6-9. IEEE Computer Society Press,
New York, pp. 126-130
78 Nicolas, J. M., and Gallaire, H. [1978]. "Data Base: Theory vs. In-
Interpretation," in Logic and Data Bases (H. Gallaire and J.
Minker, eds.), Plenum Press, New York, pp. 33-54
79 Nilsson, N. J. A980]. Principles of Artificial Intelligence, Tioga,
Palo Alto, Ca.
80 Nygaard, K., and Dahl, O. J. [1978]. The Development of the
SIMULA Languages," SIGPLAN Notices 13:8, pp. 245-272
81 O'Keefe, R. A. [1985]. "On the Treatment of Cuts in Prolog
Source-Level Tools," Proc. Symposium on Logic Programming,
Boston, Ma., July 15-18. IEEE Computer Society Press, New
York, pp. 68-72
82 Parsaye, K. [1983]. "Database Management, Knowledge Base
Management, and Expert System Development in Prolog,"
Proc. ACM Database Week, San Jose, Ca., pp. 179-183
СПИСОК ЛИТЕРАТУРЫ 455
83 Pereira, F. С. N. (ed.) [1985]. CProlog User's Manual Version 1.4,
Department of Architecture, University of Edinburgh, Edin-
Edinburgh
84 Pereira, F. С N.. and Warren, D. H. D. [1980]. "Definite Clause
ш Grammars for Language Analysis—A Survey of the For-
t'.i malism and a Comparison with Augmented Transition Net-
> works,* Artificial Intelligence 13, pp.23 Ь278
85 Pereira. F. С N.. and Warren, D. H. D. [1983]. "Parsing as Deduc-
Deduction,* Proc. 21st Annual Meeting of the Association for Com-
Computational Linguistics, MIT, June 15-17. Association for
Computational Linguistics, pp. 137-144
86 Рое, М. D. [1984]. "Control of Heuristic Search in a Prolog-Based
Microcode Synthesis Expert System," Proc. International Con-
Conference on Fifth Generation Computer Systems, Tokyo, Japan,
November 6-9. Institute for New Generation Computer Tech-
Technology, pp. 589-595
87 Pollard, С |I984] Generalized Phrase Structure Grammars, Head
Grammars, end Natural Languages, PhD Thesis, Stanford
University, Stanford, Ca.
88 Reichenbach, H [1947]. Elements of Symbolic Logic, Macmillan,
New York
89 Reitcr, R. [1978]. "On Closed World Data Base»," in Logic and
Data Bases (H Gallaire and J. Minker, eds.). Plenum Press,
New York, pp. 55-76
90 Roberts, G. M. [I977J. An Implementation of PROLOG, M.Sc.
Thesis, University of Waterloo, Ontario, Canada
91 Robinson, J. A. [1965]. "A Machine-Oriented Logic Based on the
Resolution Principle," Journal of the ACM 12, pp. 23-41
92 Robinson, J. A. [1979]. Logic: Form and Function, Elsevier-North
Holland, New York
33 Roussel, P. [1975]. PROLOG: Manuel de Reference el d'Utilisation,
University of Aix-Marseilles, Luminy, France
456 СПИСОК ЛИТЕРАТУРЫ
94 Sergot, M. [1982]. "Pror.pects for Representing the Law as Logic
Programs," in Logic Programming (K. L. Clark and S. A.
Tarnlund, eds.), Academic Press, London, pp. 3-18
9? Shapiro, E. Y. [!983a]. Algorithmic Program Debugging, The MIT
Press, Cambridge, Ma.
96 Shapiro, E. Y. {1983b}. "A Subset of Concurrent Prolog and its In-
Interpreter," ICOT Technical Report TR-003, Institute for New
Generation Computing, Tokyo
•97 Shapiro, E. Y. [1984]. "Guest Editor's Preface," New Generation
Computing 2:4, pp. 305-308
• 98 Shapiro, E. Y., and Takeuchi, A. [1983]. "Object Oriented Program-
Programming in Concurrent Prolog," New Generation Computing, 1:1,
pp. 25-48 ¦
99 Shieber, S. M.,.Uszkoreit, H., Pereira, F. С N., Robinson, J. J., and
Tyson, M. A983]. The Formalism and Implementation of
PATR-II," in Research on Interactive Acquisition and Use of
Knowledge, Artificial Intelligence Center, SRI International,
Menlo Park, Ca.
100 Siekmann, J., and Wrightson, G. (eds.) [1983a]. Automation of
Reasoning 1 Classical Papers on Computational Logic 1957-
1966, Springer-Verlag, Berlin
101 Siekmann, J., and Wrightson, G. (eds.) [1983b]. Automation of
Reasoning 2 Classical Papers on Computational Logic 1967-
1970, Springer-Verlag, Berlin
102 Simmons, R. F. [1984]. Computations from the English, Prentice-
Hail, Englewood Cliffs, N. J.
103 Swinson, P. S. [1980]. "Prescriptive to Descriptive Programming a
Way Ahead for Caad," Proc. Logic Programming Workshop,
July 14, pp. 262-273
104 Taylor, A. E. [1955]. Aristotle, Dover, New York
105 Tick, E, and Warren, D. H. D. [1984]. "Towards a Pipelined Prolog
Processor," New Generation Computing 2:4, pp. 323-346
СПИСОК ЛИТЕРАТУРЫ 457
106 Tokoro, M. and Ishikawa, Y. [1984]. "An Object-Oriented Approach
to Knowledge Systems," Proc. International Conference on
Fifth Generation .Computer Systems, Tokyo, Japan, November
6-9. Institute for New Generation Computer Technology, pp.
623-631
107 Uehara, K., Ochitani, R., Kakusho, O., and Toyoda, J. [1984]. "A
Bottom-Up Parser Based on Predicate Logic: A Survey of the
Formalism and its Implementation Technique," Proc. Interna-
International Symposium on Logic Programming, Atlantic City, N.
J., February 6-9. IEEE Computer Society Press, New York,
pp. 220-227
108 Uehara, K., Ochitani, R.. Mikami, O., and Toyoda, J. [1984]. "An
Integrated Parser for Text Understanding: Viewing Parsing as
' Passing Messages among Actors," Proc. Natural Language Un-
Understanding and Logic Programming, Rennes, France, Sep-
September 18-20, pp. 59-70
109 Uehara, Т., and Kawato, N. [1983]. "Logic Circuit Synthesis Using
Prolog," New Generation Computing 1:2, pp. 187-193
110 Warren, D. H. D, and Pereira, F. С N. [1981]. "An Efficient Easily
Adaptable System for Interpreting Natural Language Queries,"
DAI Research Paper No. 155, Department of Artificial Intelli-
Intelligence, University of Edinburgh, Edinburgh
Ш Warren, D. H. D., Pereira, L. M., and Pereira, F. С N. [1977].
"PROLOG—The Language and its Implementation Compared
with LISP," SIGPLAN Notices 12:8
X\2 Winograd, T. [1980]. "Extended Inference Modes in Reasoning by
Computer Systems," Artificial Intelligence 13, 1980, pp. 5-26
113 Yasukawa, H. [1983]. "LFG in Prolog—Toward a Formal System
for Representing Grammatical Relations," ICOT Technical
Report TR-019, Institute for New Generation Computing,
Tokyo
1W Zaniolo, С [1984]. "Object-Oriented Programming in Prolog," Proc.
International Symposium on Logic Programming, Atlantic
City, N. J., February 6-9. IEEE Computer Society Press, New
York, pp. 265-271
458 СПИСОК ЛИТЕРАТУРЫ
115 Zaumen, W. Т. [1983]. "Computer-Assisted Circuit Evaluation in
Prolog for VLSI," Proc. ACM Database Week, San Jose, Ca.,
pp. 179-183
116 van Emden, M. H., and Kowalski, R. A. [1976]. "The Semantics of
Predicate Logic as Programming Language," Journal of the
ACM 23:4, pp. 733-742
117 van Heijenoon, J. (ed.) [1967]. From Frege to Goedel: A Source
Book in Mathematical Logic 1879-1931, Harvard University
Press, Cambridge, Ma.
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ
Абстрактные аилы данных 270
Аксиома в логике высказываний 33-37
предикатов 39-40,42,45-49
-фреймов 291-292,299
Аксиоматическое определение 200,
254- 256
множества ответов 200
- отношения 46, 48, 65
Алгоритм, определение 36
- Ковальеки 65
- основанный на правиле резолю-
резолюции 57-58
поиска с возвратом 126, 155-
156, 191,194
-процедурный 171-174
- рекурсивный 47
Ассоциативность операции 169
Атомарная формула 37-38
Атомарное высказывание 29-34
База данных динамическая 291-292
—, ее состояния 291-292
неявная 85,121
реляционная 72
, состоящая из фактов 78
- - явная 85, 99, 121
Бесконечная область интерпретации 47
Бесконечный цикл 223, 305, 315-318
Бихевиорнстнческий подход к програм-
программированию 178-179, 200-203
Булева алгебра 25
Включение в класс/вхождение в состав
класса в объектно-ориентированном
формализме 271
/ в формализме се-.
мантических сетей 264
/ фреймов 265
Внешний смысл символического обозна-
обозначения 256-259
Встроенные предикаты 105-106, 112,
141-142, 152,154-174
Вычислительный формализм 36
об ьектно-о риентнрованный
268-271
, определение 252
, Пролог как вычислительный
формализм 252-259,319-321,325
семантических сетей 262—264
, сопоставление с языком Си
259
фреймов 264-268
Двоичное дерево 120,124-126
Декларативная граница 320-323, 325-
326
- семантическая модель Пролога
66-68,129
- управляющая информация 325-
326
Декларативный смысл 87-88, 142, 154,
319,322
- стиль Пролога 64
Дескриптивное программирование 62-
64
Детерминированность 106, 146, 154,
328-329
Диаграмма в виде дерева доказательст-
доказательства 92-95, 115 116
Дизъюнктивный силлогизм 22. 55
Доказательство, его автоматизация
49-50
—, — алгоритмическая верификация
36,49
- с использованием правила резо-
резолюции 55-59
460
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ
Доказательство, семантические методы
34-35, 45-46
-, синтаксические методы 34-35,
45-46
Заголовок правил? 82-83, 166
- -, квалификация переменной в
нем 84
—, унификация с ним 130-134
Законы логики 19-20, 68-69
Запрос 63,65,78-82
-, его выполнение 89
-, - входные и выходные данные
81,107
- , - подразумеваемый смысл 70,
298, 318, 325
- к правилу Hi
- как вызов процедуры 67
- составной 81, 89
Изоморфизм 14,321,325
Интерпретация 31, 43, 252, 257, 272
- алгебраических правил 25-26, 28
- в логике высказываний 31-32, 35
предикатов 43
-, область интерпретации 38-39
- Хербранда 51-53
Квалификация переменных 20-21,29,
38. 43-44, 56, 79, 84, 102, 152
Компараторы 164
Конкретизация переменный 80
Конструктор списка 111
Концепции представления знаний 261-
264,271-273,278-279
Леворекурсивная процедура 93-94,
115, 223-227, 251, 304-305, 314
Лексический анализатор 207-211, 234
Логика высказываний 29-37
- предикатов 37-49, 252-253
Логический соединитель 30-32
Метаязык 151,298, 318, 321
-, его определение 36-37, 74
-,-предикаты 71-72
-, - синтаксическое соотношение
с объектным языком 69
-, - функции 68-69
-;Пропога 70-71
Метод в объектно-ориентированном фор-
формализме 268-271,278
- работы системы восходящего
грамматического разбора 217-219
системы нисходящего грамма-
грамматического разбора 217
Микро-Пролог 74, 101-102, 229-237
-, его синтаксис 230
Множество ответов бесконечное 186,
193-196
- - неполное 147-149, 188
- упорядоченное 191-200
циклическое 186. 187, 189,
193
Модель в логике высказываний 32-35
предикатов 44-45
-Хербраида 51-53,57
Наследование значений слотов в форма-
формализме фреймов 265
~, концепция наследования 261-
262
- , механизм наследования в Проло-
Прологе 271-299
- сообщений в объектно-ориенти-
рованиом формализме 269-270
Начало списка 111
Непоследовательность 50
Нетерминал 211
Неявная база данных 85,121
Нисходящая стратегия решения задач
57-59
Обнаружение циклов 314, 316-318
Обрабатывающая структура 253, 256,
260-261,273,298,318 '
Обработка списков 112-119
Обратимая процедура 118, 127, 175
Объектно-ориентированный формализм
262,268-271,274,278,299
Объектный язык 26. 68-70, 151
Ограничения, обеспечивающие целост-
целостность 96-98, 146, 163, 180, 181 —
183, 267, 275, 287, 293, 296, 323-
325
Онтологические предположения логики
предикатов 261
Операции 168-171, 177, 203-204, 235
- арифметические 105, 395, 402,
408,414,420
- для абстрактных типов данных
270-271
-, как их определить 168-171
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ
461
Опровержение фразы в механизме насле-
наследования 277-278
Оптимизация остаточной рекурсии 392-
393
Остаток списка 111
Отношения 76, 86, 95
- в логике предикатов 37-38
-. диаграммы, иллюстрирующие нх
181
-, их аксиоматическое определение
46-48.65,255
-, - общая теория 28-29
-,- объявление 64
-, - свойства 96, 99-101, 183-
185
-, - семантическое определение
40-41
-,-тнпы 95-101
Отрицание в логике высказываний 26-
27,30
предикатов 38
- как неудача 150-151
- явное 152
Переменная в запросе 79-82, 102,107
- в правиле 82-84
- в Прологе 64
- во фразовой форме 56-58
-, ее внутреннее обозначение 119
-, - квалификация 29, 43-44,
47
-, в запросе 79, 102
-, — в правиле 84
- пропозициональная 30, 32, 35
Планирование производственных опера-
операций 197 199, 339-380
Побочные эффекты ввода/вывода 154
- - управления 129, 173, 200-203,
260, 273, 279, 297, 319-321, 322,
325-326
Шдход к программированию с позиций
потока данных 178-179, 190-200
Поиск с возвратом 126, 130, 135
Понятие "кпасс" в объектно-ориентиро-
объектно-ориентированном формализме 268-271, 278
Правило вывода 22, 35-36, 47, 252
- с помощью метода резолюции
55,57-59
Правильно построенная формула (ППФ)
в логике высказываний 30-31
. предикатов 38
Праворекурсивиое правило 214-217, 251
Предикат в силлогистической логике 20
- встроенный 105-106, 112, 141-
142^152. 154-171
-, его определение 77
-, - символическое обозначение
38,41,42
-, определение Фреже 28
- , определяемый множеством фак-
фактов 77-78
-,- правилом 83-84
- "обр_порядок" 333
- "один раз" 149-150, 173
- "сократить" 97, 129, 141-150.
155, 158, 167, 182-184, 289, 310
—, его влияние на процедуру
143-146
, - «- на составной запрос 142
—, - ненужное влияние 187-188,
272
, - применение для наложения
ограничений, обеспечивающих це-
целостность отношений 182-183
, — для придания процедуре
детерминированности 145-146
как подцель 142
, ограничение области его дейст-
действия 148-150
- "assert" 159-163, 173-174, 201,
296,333-334,361,366,380
- "atom" 77,80,96,107
—, определение 77
- "clause" 166, 308, 309, 317, 324
- "fmdall" 167-168, 174-175,
203,320,325,326
, его реализация 333-334
как расширение обрабатываю-
обрабатывающей структуры Пролога 25 3, 260,
298
- "name" 165-166, 209, 231-232,
308
- "not" 152, 153
- "repeat" 167, 176, 193, 237, 250
- "retract" 160, 163, 174, 296, 334
- "see" 156,167
- "tell" 156
Предположение о замкнутости мира
70-71, 150, 181-182
- об открытости мира 151
Представление знаний 64-66, 73, 252
- — в вычислительном формализ-
формализме 253-255
- в языке Си 259
462
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ
Пример с миром кубиков 292-297,
335-336
- с птицами 262-264, 269-271,
279-280
- с собранием 264-268, 271-272,
277-279
- с экологическим процессом 193 —
197
Программа "вид" ("видимый Пролог")
141,304, 310-314
- "восхобъект" (выполняет вос-
восходящий грамматический разбор)
217-229,304
- "вып" (выполняет запросы) 305-
309.324
- "ген чисел" (генератор чисел)
346
- "запросбд" (экранно-ориентиро-
ванная программа выполнения за-
запроса) 336-339
- "иоц" (интерпретатор, обнаружи-
обнаруживающий циклы) 304-305, 314-
318,326
как метаязыковой предикат
318
- "найтиилиспроснть" 201-202,
205.325
- "объект" (нисходящий граммати-
грамматический разбор) 212-217, 229,
240-242
- "отобразить_ состояние" (мира
кубиков) 294-295, 335-336
- "поместить" (программа сбора
данных) 296, 326-327
- "рз" (решатель задач) 324—325
как предикат метаязыка 325
- "сп неповт знач" 334
- "читатьпредл" (лексический ана-
анализатор) 208-211,234,250-251,406
Пространство поиска запроса 141-
142,183
Противоречие 20,32-33,69
- в процедуре опровержения 51
- при резолюции 57-59
Процедура опровержения 50-51, 53, 57
- "вводполя" 165-166, 290, 334-
335,338
- "послать" 273-277, 279-282,
288-291, 296-298, 318, 325, 326
как предикат метаязыка 298
- "схема" 237-239, 241, 245-
246, 336
Процедурная семантика логики 59,
66-67
Процедурный алгоритм 171-174
- смысл 87-88,93, 154
Путь доказательства 305-310
Реляционная база данных 72
Рекурсивная процедура 90-95, 109,
114, 172
- разрешимость 49
-структура 108-110,123
Рекурсивный алгоритм 47, 90-91, 195,
197
Рефлексивность 96, 99-1-01, 180, 183-
184. 190,293
Сбор данных 293
Свойство двунаправленности аргумента
107,118,127,213,235
Семантика логики высказываний 31 — 33
Семантическая модель Пролога в виде
абстрактной машины 67, 129
- сеть 262-264, 299
, реализующая ее Пролог-прог-
Пролог-программа 263-264,299-300
Семантические модели Пролога 66-68,
129
- свойства формул 44-45
Семантическое определение функций и
отношений 40-41
Силлогизм 21-24
Симметрия 25, 96, 98-100, 180, 183—
186, 190,293
Система восходящего грамматического
разбора 73, 206, 217-229, 251
, ее стратегия 207, 217
, используемые в ней лево-
леворекурсивные правила 223-228
- нисходящего грамматического
разбора 206, 211-215, 228-229,
231,239,251
, ее стратегия 207, 216-217
' , используемые в ней лево-
леворекурсивные правила 223-224
Смысл внешний 256-259
- декларативный 66-67, 83, 85-
86,141-142, 154,260,273
- дескриптивной программы 252-
253,319-320
- неформальный 29, 33-34, 36
- процедурный 87-88, 93, 154
- символического обозначения
256-258
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ
463
Соединитель 30-31, 240
- "или" 89-90
- неявный 88
Состояния базы данных 291-292
- знаний 272-274, 278-280, 298
Стиль программирования 76, 113, 174,
178, 180, 200-202, 260-261, 318-
323,325-326,383
Стратегии решения задач 57, 59, 70-71,
207,298,304,318
Структура (составной терм) 107-110
- "./2" 110-113
- области знаний 33, 39-40, 64-66
- системы 253-254, 277, 291
Тавтология 32-33,69
Тело правила 82-83
—, квалификация переменных
в нем 84
Теория 252-253
- в логике высказываний 31, 32
- во фразовой форме 56-58
-, ее интерпретация 43
-, - полнота и последователь-
последовательность 37
-, - следствие 45, J 3
-, - сходство с Пролог-програм-
Пролог-программой 65, 252-254
- модели 298
- ¦ области знаний 33, 39
Терминал 211
Традиционная логика 19-24
Транзитивность 96, 100-101, 181, 185—
190,293,299,306
- отношения включения в класс 21
Удовлетворительный 44-45
Унификация 112, 129-138, 243, 310
- при резолюции 56
- списков 113
Управление, определение Ковальски 66
- файлами 156-157, 167, 388-389,
394, 401-402, 407-408, 419-420
Формализм фреймов 264-268
— в сравнении с механизмом на-
наследования Пролога 278
— с обьектио-ориентироваи-
ным формализмом 271
-—, его реализация с помощью
Пролог-программы 266
Формальный смысл дескриптивной прог-
программы 253-255, 318-319
— символического обозначения
256-259
Фраза Хорна 17-18
-—, записываемая на Прологе 62
63
как форма логики предика-
предикатов 53-55
—, квалификация переменных в
ней 56
фразовая форма 53-56
Функция арифметическая 105, 395, 402,
408,414,420
-, ее анализ 39,64
-, - определение 40
-, - семантическое определение 41,
65
-, - синтаксис 38
- "следующий за" 47
Экспертная система 73, 302-303, 326
Экспертные консультации 302-303
Явная база данных 85, 99,121
Язык запросов 237-250
Научное издание
МАЛПАСДжон :;i
РЕЛЯЦИОННЫЙ ЯЗЫК ПРОЛОГ И ЕГО ПРИМЕНЕНИЕ |
Заведующий редакцией А.С. Косое. Редактор Т.Ч. Пташник \
Художественный редактор Т.Н. Кольченко /
Технические редакторы О.Б. Черняк, ММ. Мешкова *
Корректоры ИМ. Круглоаа, ТА. Иечко I
Набор осуществлен в издательстве на наборно-печатающих автоматах ]
ИБ № 30996 ]
Сдано в набор 21.05.90. Подписано к печати 10.10. 90. Формат 60 X 88/16
Бумага книжно-журнальная. Гарнитура Пресс-Роман. Печать офсетная
Усл.печ л. 28,42.Усл.кр.отт. 28,42. Уч.-изд.л. 28,97
Тираж 57 700 экз. Тип. эак. 52. Цена 3 р. 50 к.
Ордена Трудового Красного Знамени издательство "Наука"
Главная редакция физико-математической литературы
117071 Москва В-71, Ленинский проспект, 15
Типография им. Котлякова
издательства "Финансы и статистика"
Государственного комитета СССР по делам издательств,
полиграфии и книжной торговли
195273 Ленинград, ул. Руставели, 13
' Л