Все права на текст принадлежат автору: У Клоксин, К Меллиш.
Это короткий фрагмент для ознакомления с книгой.
Программирование на языке ПрологУ Клоксин
К Меллиш

У.Клоксин, К.Меллиш ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ ПРОЛОГ Для программистов и пользователей ЭВМ.

ПРЕДИСЛОВИЕ РЕДАКТОРОВ ПЕРЕВОДА

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

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

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

В социалистических странах активное участие в разработках, связанных с Прологом, принимают ученые ВНР. В Институте по координации вычислительной техники (г. Будапешт) создана версия Пролога – МПролог, получившая международное признание. Не исключено, что МПролог будет широко доступен и пользователям нашей страны. Этим объясняется включение в русское издание специального приложения (F) посвященного МПрологу.

При переводе книги встретились значительные терминологические проблемы, поскольку установившаяся русская терминология в данной области практически отсутствует, а станет ли таковой англоязычный жаргон специалистов – покажет время. Для удобства читателей в предметном указателе приведены английские эквиваленты терминов, употребляемых в переводе.

Предисловие, главы 1,3-6, 9, 10 и Приложение В перевел М. М. Комаров, главы 7, 8, 11, Приложения А,С, D, E, F- А. В. Горбунов, главу 2 – Ю. М. Лазутин.

ПРЕДИСЛОВИЕ КО ВТОРОМУ ИЗДАНИЮ

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

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

У. Клоксин К. Меллиш

Кембридж, Англия, август 1984

ПРЕДИСЛОВИЕ К ПЕРВОМУ ИЗДАНИЮ

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

• реляционные базы данных,

• математическую логику,

• решение абстрактных задач,

• понимание естественного языка,

• автоматизацию проектирования,

• символьное решение уравнений,

• анализ биохимических структур,

• различные области искусственного интеллекта.

До настоящего времени не было книг, ставивших своей целью обучить Прологу как языку практического программирования. Видимо, Пролог оказался настолько привлекательным для многих людей, что они стали его изучать, используя неизбежно краткие справочные руководства, небольшое число опубликованных статей и передаваемый устно среди пользователей языка «фольклор». Однако с внедрением Пролога в учебные программы для студентов и аспирантов многим из наших коллег понадобилось учебное руководство по Прологу. Мы надеемся, что наша небольшая книга до некоторой степени удовлетворит эту потребность.

Многие новички обнаруживали, что задача написания программы на Прологе не похожа на спецификацию алгоритма при программировании на традиционном языке программирования. Программист, использующий Пролог, больше интересуется тем, какие формальные отношения и объекты имеют место в решаемой задаче и какие отношения справедливы для разыскиваемого решения. Таким образом, Пролог можно рассматривать как язык описаний, а не как язык предписаний. Используемый в Прологе подход состоит главным образом в описании известных фактов и отношений, касающихся решаемой задачи, а не в предписании последовательности шагов, выполняя которые ЭВМ решит задачу. При реализации программы на Прологе фактическая последовательность вычислений, выполняемая ЭВМ, определяется частично логической декларативной семантикой Пролога, частично новыми фактами, которые Пролог может «вывести» из заданных ему фактов, и лишь отчасти управляющей информацией, явно заданной программистом.

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

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

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

Как и большинство других языков программирования, Пролог существует в множестве различных реализаций, каждая со своими семантическими и синтаксическими особенностями. Для описания в этой книге выбран «базовый» Пролог и все приводимые примеры написаны для стандартной версии, которая соответствует реализациям, разработанным главным образом в Эдинбурге для нескольких различных вычислительных систем: DEC-10 с операционной системой TOPS-10, DEC VAX и PDP-11 с операционной системой Unix, DEC LSI-11 с операционной системой RT-11 и ICL2980 с операционной системой ЕМА. Реализации для ЭВМ фирмы DEC являются, вероятно, наиболее распространенными. Все примеры, приведенные в этой книге, подходят для всех указанных реализаций. В приложениях приведены описания некоторых из существующих реализаций Пролога с указанием их отличий от стандарта. Читатель сможет убедиться, что большинство отличий имеет чисто «косметическую» природу.

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

Каждая глава книги делится на несколько разделов, и мы советуем читателю выполнять упражнения, приводимые в конце многих разделов. Решения к некоторым из этих упражнений даны в конце книги. Глава 1 представляет собой введение, цель которого – дать читателю почувствовать характер программирования на Прологе. Здесь вводятся основные идеи языка Пролог и читателю рекомендуется тщательно изучить их. В гл. 2 содержится более полное обсуждение идей и понятий, введенных в гл. 1. В гл. 3 рассматриваются структуры данных и приводятся в качестве примеров несколько небольших программ. В гл. 4 более подробно обсуждается механизм возврата, вводится символ «отсечения», используемый для управления механизмом возврата. В гл. 5 вводятся имеющиеся в языке средства ввода-вывода. В гл. 6 описывается каждый встроенный предикат базовой версии языка Пролог. Глава 7 представляет собой «попурри» из примеров программ, взятых из многих источников и снабженных комментариями, поясняющими их работу. В гл. 8 даются некоторые советы по отладке программ на Прологе. В гл. 9 вводится синтаксис грамматических правил и изучаются предположения, лежащие в основе программ для анализа естественного языка с использованием грамматических правил. В гл. 10 описывается связь Пролога с идеями математического доказательства теорем и логического программирования, лежащими в основе языка. В гл. 11 представлен ряд проектов, на которых заинтересованные читатели могут поупражняться в развитии навыков программирования на Прологе.

Мы выражаем благодарность нашим учителям, сформировавшим наши взгляды на программирование: Роду Борстоллу, Питеру Скотту Лэнгстону и Робину Попплстоуну. Мы благодарны друзьям, участвовавшим вместе с нами в совершенствовании Пролога как практического и полезного средства программирования и поддерживавших нас в процессе подготовки этой книги: Алану Банди, Лоренсу Байрду, Роберту Ковальски, Фернандо Перейра и Дейвиду Уоррену. В частности, Лоуренс Байрд поддерживал работу по созданию книги с самого ее начала, предлагая программы, упражнения, некоторые проекты, приведенные в гл. 11, и много идей по организации книги. Мы также благодарны нашим друзьям, внесшим свой вклад в создание книги полезными замечаниями и советами по улучшению предварительного ее варианта: Джону Каннингаму, Ричарду О'Кифу, Элен Пейн, Фернандо Перейра, Гордону Плоткину, Роберту Реи, Питеру Россу, Максвеллу Шортеру, Арону Сломену и Дейвиду Уоррену. В этом отношении У. Клоксин особенно благодарен своим аспирантам из School of Epistemics и Department of Artificial Intelligence, которые помимо их воли стали объектом многочисленных экспериментов в области обучения программированию. При выборе примеров мы свободно пользовались распространенным программистским фольклором и в связи с этим приносим наши извинения всем, кто чувствует себя обойденным вниманием.

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

У. Клоксин К. Меллиш

Эдинбург, Шотландия, июнь 1981

ГЛАВА 1 ВВЕДЕНИЕ

Пролог – язык программирования, используемый для решения задач, сводимых к объектам и отношениям между объектами. В этой главе мы продемонстрируем основные элементы языка на примерах реальных программ, не вдаваясь особенно в детали, формальные правила и исключения. Исходя из этого, мы не старались, чтобы изложение было полным или достаточно точным. Мы хотим как можно быстрее подвести вас к тому моменту, когда вы сможете самостоятельно писать полезные программы, и чтобы добиться этого, мы должны сконцентрировать внимание на основных понятиях: фактах, запросах, переменных, конъюнкциях и правилах. Другие особенности языка Пролог, такие как списки и рекурсия, будут рассмотрены в последующих главах.

Пролог применяется в тех случаях, когда необходимо использовать ЭВМ для решения задачи, которая может быть выражена в терминах объектов и отношений между ними. Например, когда мы говорим: «Джон имеет книгу», мы объявляем, что между одним объектом «Джон» и другим объектом «книга» имеет место отношение обладания. Более того, это отношение имеет определенный порядок: Джон имеет книгу, но книга не имеет Джона! Когда мы задаем вопрос: «Имеет ли Джон книгу?», то нас интересует правильность именно отношения.

При констатации некоторых отношений не всегда упоминаются все объекты, включаемые в них. Например, когда мы говорим: «Драгоценные камни являются ценными», мы имеем в виду, что существует отношение, называемое «являться ценным», которое включает драгоценные камни. Для нас не имеет значения, кто считает, что драгоценные камни являются ценными, и почему он так считает. Это все зависит от того, что вы хотите сказать. При использовании Пролога, когда программируются отношения, подобные приведенным, уровень требуемой детализации также зависит от того, что вы хотите заставить делать ЭВМ.

Существует еще один вопрос идейного плана, который следует упомянуть, прежде чем приступать к программированию. Мы все знакомы с использованием правил для описания отношений между объектами. Например, правило «Два человека являются сестрами, если они оба женского пола и имеют одних и тех же родителей» объясняет нам, что значит быть сестрами. Оно также указывает, как определить, являются ли два человека сестрами: необходимо просто проверить, относятся ли они оба к женскому полу и имеют ли одних и тех же родителей. Важно отметить, что хотя правила обычно бывают упрощенными, тем не менее они приемлемы в качестве определений. В конце концов, не следует ожидать, что определение говорит нам все об определяемом объекте. Например, большинство людей согласится с тем, что в реальной жизни «быть сестрами» значит больше, чем это следует из приведенного правила. Однако, решая конкретную задачу, необходимо сосредоточить внимание именно на таких правилах, которые помогут ее решить. Таким образом, следует обратиться к схематичному и упрощенному определению, если его достаточно для достижения поставленной цели.

Программирование на языке Пролог состоит из следующих этапов:

• объявления некоторых фактов об объектах и отношениях между ними,

• определения некоторых правил об объектах и отношениях между ними и

• формулировки вопросов об объектах и отношениях между ними.

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

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

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

1.1. Факты

Начнем обсуждение с фактов об объектах. Предположим, мы хотим сообщить Прологу[1]факт: «Джону нравится Мэри». Этот факт включает в себя два объекта, обозначенных именами «Мэри» и «Джон», и отношение, обозначенное словом «нравится». В языке Пролог используется стандартная форма записи фактов:


нравится (джон, мэри).


Важно соблюдать следующие правила:

• Имена всех отношений и объектов должны начинаться со строчной буквы. Например, нравится, джон, мэри.

• Сначала записывается имя отношения. Затем через запятую записываются имена объектов, а весь список имен объектов заключается в круглые скобки.

• Каждый факт должен заканчиваться точкой.

Определяя с помощью фактов отношения между объектами, необходимо учитывать, в каком порядке перечисляются имена объектов внутри круглых скобок. Этот порядок может быть произвольным, но, выбрав один раз какой-то определенный порядок, мы должны везде следовать ему и далее. Например, в приведенном выше факте мы поставили на первое место в списке объектов «того, кому нравится», а объект «который нравится» стоит во второй позиции. Таким образом, факт нравится(джон,мэри) не одно и тоже, что нравится(мэри,джон). В соответствии с принятой нами (хотя и произвольным образом) договоренностью первый факт говорит о том, что Джону нравится Мэри, в то время как второй факт говорит, что Мэри нравится Джон. Если мы хотим сказать, что Мэри нравится Джон, то мы должны сформулировать это утверждение явно, в виде факта


нравится(мэри,джон).


Взгляните на следующие примеры фактов, приведенные вместе с возможной их интерпретацией на естественном языке:

ценный(золото). Золото является ценным,

женщина(джейн). Джейн — женщина.

владеет(джон,золото). Джон владеет золотом.

отец(джон,мэри). Джон является отцом Мэри.

дает(джон,книга,мэри). Джон дает Мэри книгу.

Всякий раз когда используется некоторое имя, оно указывает на определенный индивидуальный объект. В силу жизненного опыта нам совершенно ясно, что имена джон и джейн относятся к индивидуальным объектам. Но в некоторых других фактах мы использовали имена золото и ценный, и совсем не очевидно, что они значат. Логики называют имена такого сорта «словами, не имеющими определенного значения вне контекста». Используя такие имена, мы должны решить, как интерпретировать эти имена. Например, имя золото могло бы относиться к некоторому объекту. В этом случае мысленный образ объекта имеет вид конкретного куска золота, который мы обозначаем именем золото. И когда мы записываем на Прологе ценный(золото), мы должны понимать это в том смысле, что этот конкретный кусок золота, для обозначения которого мы использовали имя золото, является ценным. С другой стороны, мы могли бы интерпретировать имя золото как слово, обозначающее химический элемент золото с атомным весом 79, и, когда мы записываем ценный(золото), мы должны понимать это так, что химический элемент золото является ценным. Таким образом, имеется несколько способов интерпретировать имя и именно автор программы определяет конкретную интерпретацию. До тех пор пока последовательно используется одна и та же интерпретация имен, никаких проблем не возникает. Выявлять отличия между различными интерпретациями необходимо с самого начала, с тем чтобы быть совершенно уверенным в том, что обозначают,имена.

Теперь пришла пора сказать несколько слов о терминологии. Имена объектов, список которых в каждом факте заключен в круглые скобки, называются аргументами. Заметим, что в программировании значение слова «аргумент» не имеет ничего общего с его общеупотребительным значением, используемым в контексте слов «диспут», «дебаты», «дискуссия», «спор» и т. п. Имя отношения, которое записывается непосредственно перед круглыми скобками, называется предикат.[2] Таким образом, ценный – это предикат, имеющий один аргумент, а нравится – предикат с двумя аргументами.

Имена объектов и отношений являются полностью произвольными. Например, вместо терма нравится(джон,мэри) мы могли бы с таким же успехом представить это как a(b,c), помня при этом, что а значит нравится, b означает Джон, а сМэри. Однако обычно мы выбираем имена таким образом, чтобы они сами напоминали нам, что они значат. Следовательно, мы заранее должны решить, что значат наши имена и каким должен быть порядок аргументов. С этого момента необходимо последовательно придерживаться принятых соглашений.

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


играть(джон,мэри,футбол).

играть(джейн, джим,бадминтон).


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

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

Совокупность фактов в Прологе называется базой данных. Мы будем пользоваться термином база данных всякий раз при объединении вместе некоторых фактов (а в дальнейшем и правил) для совместного их использования при решении некоторой конкретной задачи.

1.2. Вопросы

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

?- имеет(мэри, книга).

Если мы интерпретируем мэри как человека по имени Мэри, а книга - это какая-то конкретная книга, то смысл вопроса в следующем: «Имеет ли Мэри (данную конкретную) книгу?» или «Имеет ли место факт, что Мэри имеет данную книгу?». Мы не спрашиваем, имеет ли она все книги или книги вообще.

Обращение к Прологу с вопросом инициирует процедуру поиска в базе данных, ранее введенной в систему. Пролог ищет факты, сопоставимые с фактом о вопросе. Два факта сопоставимы (или соответствуют один другому), если их предикаты одинаковы (побуквенное совпадение) и их соответствующие аргументы попарно совпадают. Если Пролог находит факт, сопоставимый с вопросом, то он отвечает да[3]. Если в базе данных такого факта не существует, то Пролог отвечает нет. Ответ, выдаваемый Прологом, выводится на дисплей терминала непосредственно под запросом. Пусть имеется следующая база данных:


нравится(джо,рыба).

нравится(джо,мэри).

нравится(мэри,книга).

нравится(джо,книга).


Если все эти факты введены в Пролог-систему, то можно было бы делать следующие вопросы, ответы на которые Пролог написал бы непосредственно под текстом вопроса:

?- нравится(джо,деньги).

нет

?- нравится(мэри,джо).

нет

?- нравится(мэри,книга).

да

?- король(джон,франция).

нет


Ответы на три первых вопроса должны быть понятны. Кроме этого, Пролог отвечает нет на вопрос о том, является ли Джон королем Франции. Система выдает такой ответ, так как среди фактов в базе данных, представленной приведенными выше четырьмя отношениями нравится, нет отношений, указывающих на королевские звания. В Прологе ответ нет используется в смысле ничто в базе данных не согласуется с вопросом. Важно помнить, что ответ нет вовсе не эквивалентен ответу является ложным. Предположим, например, что база данных содержит три факта об известных мыслителях Греции:


человек(сократ).

человек(аристотель).

афинянин(сократ).


Можно было бы сделать несколько вопросов:


?- афинянин(сократ).

да

?- афинянин(аристотель).

нет

?- грек(сократ).

нет


Хотя тот факт, что Аристотель жил когда-то в Афинах, может быть исторически верным, мы просто не можем доказать его на основе фактов, представленных в базе данных. Более того, хотя в базе данных содержится факт о том, что Сократ жил в Афинах, это не доказывает того, что он был греком, если только в базе данных нет дополнительной информации. Таким образом, когда Пролог на вопрос отвечает нет, это значит не доказуемо, не согласуется с базой данных.

В приведенном ранее примере Джону и Мэри нравится один и тот же объект. Мы знаем, что им нравится один и тот же объект, так как одно и то же имя книга появляется в обоих фактах.

Обсуждавшиеся до сих пор факты и вопросы не представляют большого интереса. Все что мы можем сделать – это получить обратно ту же самую информацию, которую мы ввели в систему. Более полезны были бы вопросы вида: «Какие объекты нравятся Мэри?». Именно для реализации такой возможности предназначены переменные.

1.3. Переменные

Если вы хотите узнать, что нравится Джону, то было бы утомительно спрашивать «Нравятся ли Джону книги?», «Нравится ли Джону Мэри?» и так далее, получая каждый раз ответ да или нет. Более разумно обратиться к Пролог-системе с просьбой назвать что-нибудь, что нравится Джону. Такой вопрос можно сформулировать следующим образом««Нравится ли Джону X?». Задавая вопрос, мы не знаем, для обозначения какого объекта использована литера X. Нам хотелось бы, чтобы Пролог перечислил все имеющиеся возможности для обозначения какого объекта использована литера X. В Прологе можно не только присваивать имена конкретным объектам, но и использовать имена, подобные X, для обозначения объектов, которые должны быть определены Пролог-системой. Имена такого типа называются переменными. Переменная в Прологе может иметь либо не иметь конкретное значение. Переменная конкретизирована, если имеется объект, который обозначает эта переменная. Переменная не конкретизирована, если еще не известно, что именно она обозначает. В Прологе используется соглашение, позволяющее отличать переменные от имен конкретных объектов – каждое имя, начинающееся с прописной буквы, рассматривается как переменная.

При поиске ответа на вопрос Пролог организует просмотр всех фактов в базе данных, чтобы обнаружить объект, который эта переменная могла бы обозначать. Так, когда мы спрашиваем «Нравится ли Джону X?», Пролог просматривает все известные ему факты для обнаружения тех вещей, которые нравятся Джону.

Такая переменная, как X, сама по себе не является именем какого-то конкретного объекта, но она может быть использована для обозначения объектов, которым мы не можем дать имя. Например, мы не можем чему-то, что нравится Джону, дать имя как объекту, поэтому для выражения подобных вопросов вместо вопросов вида


?- нравится(джон, Что-то, что любит Джон).


Пролог позволяет использовать переменные и задавать вопросы в виде


?- нравится(джон,Х).


При желании можно давать переменным более длинные имена. Следующий вопрос вполне приемлем в Прологе:

?- нравится(джон, Что-точтонравитсяджону).

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


нравится (джон,цветы).

нравится (джон,мэри).

нравится(поль,мэри).


?- нравится(джон,Х).


В вопросе спрашивается: Существует ли что-нибудь, что нравится Джону? В ответ Пролог напечатает:


Х=цветы


а затем будет ждать дальнейших приказов; это мы вкратце обсудим далее. Как это произойдет? При поступлении такого вопроса в Пролог-систему переменная, входящая в вопрос, изначально является неконкретизированной. Пролог просматривает базу данных в поисках факта, сопоставимого с вопросом. Если неконкретизированная переменная появляется в качестве аргумента, то Пролог считает, что такой аргумент сопоставим с любым другим аргументом, находящимся в той же самой позиции факта. В нашем примере Пролог ищет любой факт с предикатом нравится и первым аргументом джон. Второй аргумент в этом случае может быть каким угодно, так как в вопросе вторым аргументом является неконкретизированная переменная. При обнаружении такого факта переменная X становится конкретизированной, обозначая объект, являющийся вторым аргументом найденного факта, каким бы этот аргумент ни был. Пролог просматривает факты базы данных в том порядке, в каком они вводились (на печатной странице это соответствует просмотру сверху вниз), поэтому факт нравится(джон, цветы) найден первым. С этого момента переменная X обозначает объект цветы или, говоря другими словами, переменная X конкретизируется значением цветы. Пролог с помощью специального маркера отмечает место в базе данных, в котором произошло сопоставление. Обсудим кратко причины, по которым оказалось необходимым использование такого маркера.

Обнаружив факт, соответствующий вопросу, Пролог печатает имена объектов, которые теперь обозначают переменные. В нашем примере есть только одна переменная X, которой соответствует объект цветы. Затем Пролог ждет дальнейших указаний, как об этом говорилось выше. Если в этой ситуации нажать на терминале клавишу RETURN, указывая тем самым, что вы удовлетворены полученным ответом, то Пролог прекратит дальнейший поиск в базе данных. Если вместо этого нажать клавишу ; (и вслед за ней клавишу RETURN), то Пролог продолжит поиск в базе данных, начиная с места, отмеченного маркером. В такой ситуации, когда Пролог начинает поиск не с начала базы данных, а с места, отмеченного маркером, мы говорим, что Пролог пытается заново согласовать вопрос.

Предположим, что в ответ на первое найденное Прологом соответствие (Х=цветы) мы предлагаем системе продолжить поиск (введя ;). Это значит, что мы хотим согласовать вопрос иначе; мы хотим найти другой объект, который могла бы обозначать переменная X. Это также значит, что Пролог должен «забыть» о том, что переменная X обозначает цветы, и снова продолжить поиск с неконкретизированной переменной X. Так как мы ищем альтернативное решение, то поиск продолжается с места, отмеченного маркером. Следующий найденный системой факт, соответствующий вопросу, есть нравится(джон,мэри). Переменная X вновь становится конкретизированной, обозначая мэри, а Пролог отмечает маркером факт нравится(джон,мэри). Пролог напечатает Х=мэри и будет ожидать дальнейших команд. Если мы вновь введем точку с запятой, то Пролог продолжит поиск. В нашем примере нет больше ничего, что нравится Джону. Поэтому Пролог завершит поиск и предоставит нам возможность сделать новые запросы или ввести новые факты.

Что произойдет, если, имея те же факты, что и ранее, мы зададим вопрос:


?- нравится(Х,мэри).


В этом вопросе спрашивается: «Существует ли объект, которому нравится Мэри?». Теперь вы сами можете понять, что в примере объектами, которые нравятся Мэри, являются джон и поль. Опять, если бы мы хотели увидеть все варианты, мы должны были бы вводить; после каждого ответа, выдаваемого Прологом:

?- нравится(Х, мэри). наш вопрос

Х=джон; первый ответ. Мы вводим ;

Х=поль; второй ответ. Вновь вводим ;.

нет больше ответов нет.

1.4. Конъюнкции

Предположим, что мы хотим получать ответы на вопросы о более сложных отношениях, таких как: «Нравятся ли Джон и Мэри друг другу?». Один из способов сделать это – узнать сначала, нравится ли Джону Мэри, и если Пролог ответит да, то спросить, нравится ли Мэри Джон. Таким образом, эта задача состоит из двух «целевых утверждений» (или целей), которые Пролог должен согласовать. Ввиду того что подобная комбинация часто используется при программировании на Прологе, для нее имеется специальное обозначение. Предположим, мы имеем следующую базу данных:


нравится(мэри,пища).

нравится(мэри,вино).

нравится(джон,вино).

нравится(джон,мэри).


Мы хотим узнать, нравятся ли Джон и Мэри друг другу. Для этого мы спрашиваем: «Нравится ли Джон Мэри и нравится ли Мэри Джон?». Связка и выражает тот факт, что нас интересует конъюнкция двух указанных целей – мы хотим последовательно согласовать с базой данных обе цели. Мы выражаем это в вопросе, записывая обе цели через запятую:


?- нравится(джон,мэри),нравится(мэри,джон).


Запятая читается как «и» и используется для разделения произвольного числа различных целей, которые должны быть согласованы с базой данных для того, чтобы ответить положительно на вопрос. Если задана последовательность целей (разделенных запятыми), то Пролог пытается согласовать каждую цель по очереди, просматривая базу данных в поисках сопоставимых фактов. Чтобы согласовать с базой данных последовательность целей, необходимо согласовать все отдельные цели. Что должен напечатать Пролог в ответ на приведенный выше вопрос? Ответ будет нет. Действительно, так как имеет место факт, что Джону нравится Мэри, то первая цель согласуется с базой данных. Однако вторая цель не согласуется с базой данных, так как в ней отсутствует факт нравится(мэри,джон). Учитывая, что мы хотели знать, нравятся ли они оба друг другу, окончательным ответом на вопрос является нет.

Сочетая возможности конъюнкции и использования переменных, можно строить достаточно содержательные вопросы. Теперь, когда мы знаем, что нельзя выяснить, нравятся ли Джон и Мэри друг другу, мы спрашиваем: «Существует ли что-нибудь такое, что нравится обоим - Джону и Мэри?». Этот вопрос также содержит две цели:

• Существует ли такой объект X, который нравится Мэри.

• Нравится ли Джону найденное значение X.

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


?- нравится(мэри,Х), нравится(джон,X).


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

Важно помнить, что каждая цель имеет свой собственный маркер для указания места в базе данных, где найдены соответствующие им факты. Если, однако, вторая цель не согласуется с базой данных, то Пролог попытается найти новое соответствие для предыдущей цели (в данном случае для первой цели). Помните, что Пролог полностью просматривает базу данных для каждой из целей. Если случится так, что некоторый факт в базе данных можно сопоставить с заданной целью, то Пролог отметит это место в базе данных на случай, если впоследствии он будет вынужден снова искать для этой цели другое соответствие. И когда возникнет необходимость найти для цели другое соответствие, Пролог начнет поиск не с начала базы данных, а с места, отмеченного маркером, соответствующим этой цели. Наш предыдущий вопрос: «Существует ли что-нибудь, что нравится и Мэри и Джону?» иллюстрирует пример такого поиска с возвратом («бектрекинга»). Пролог выполняет следующую последовательность действий:

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

2. Теперь в базе данных ищется факт нравится(джон,пища), так как следующая цель – это нравится (джон,X), а переменная X теперь имеет значение пища. Как можно видеть, база данных такого факта не содержит, так что эта цель с базой данных не согласуется. В этой ситуации мы должны попытаться найти новое соответствие в фактах для предыдущей цели. Поэтому Пролог предпринимает попытку найти новое соответствие для нравится(мэри,X), при этом поиск в базе данных начинается с отмеченного маркером места. Но сначала необходимо «расконкретизировать» переменную X так, чтобы X опять могла быть сопоставлена с любым объектом.

3. Отмеченным маркером местом является факт нравится(мэри, пища). Поэтому Пролог начинает поиск со следующего непосредственно за ним факта. Так как мы еще не достигли конца базы данных, то мы не исчерпали всех объектов, которые нравятся Мэри. Следующим сопоставимым фактом является нравится(мэри, вино). Теперь переменная X принимает значение вино, и Пролог отмечает это место на случай, если потребуется найти новое соответствие для того, что нравится Мэри.

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

5. Теперь обе цели согласованы. Переменная X обозначает имя вино. Маркер первого целевого утверждения отмечает в базе данных факт нравится(мэри,вино), а маркер второго целевого утверждения отмечает факт нравится(джон,вино).

Как и в случае других запросов, как только Пролог находит ответ, он прекращает поиск и ожидает дальнейших указаний.

Если ввести ;, то Пролог продолжит поиск объектов, которые нравятся одновременно Джону и Мэри. Теперь мы знаем, что все последующие попытки поиска новых ответов на вопрос с двумя целями начинаются с мест, отмеченных маркерами, которые оставили эти цели на предыдущем этапе.

Подводя итог, можно представить конъюнкцию целей в вопросе как список целей, упорядоченных слева направо и разделенных запятыми. Каждая цель может иметь соседа слева и соседа справа. Ясно, что цели, занимающие в списке крайнее левое и крайнее правое положения, не будут иметь соседей соответственно слева и справа. Обрабатывая конъюнкцию целей, Пролог пытается по очереди согласовать с базой данных каждую цель, просматривая вопрос слева направо. Если обнаруживается факт, сопоставимый с целью, то Пролог оставляет в этом месте базы данных маркер, связанный с целью. Это можно наглядно представить с помощью стрелки, ведущей от цели к некоторому месту в базе данных, где находится соответствующий факт. Кроме того, некоторые ранее неконкретизированные переменные могут при этом быть конкретизированы, как это имело место выше на шаге 1. Если некоторая переменная конкретизируется, то конкретизируются и все вхождения этой переменной в вопрос. Далее Пролог пытается удовлетворить правого соседа этой цели, начиная поиск с вершины базы данных (наполнение базы данных в Прологе осуществляется сверху вниз, так что вершина – это факт, внесенный в базу данных первым). Как и любая другая цель, для которой найдено соответствие, она оставляет после себя в базе данных маркер (проводит еще одну стрелку от этой новой цели к соответствующему ей факту), на случай если впоследствии возникнет необходимость найти для цели другое соответствие. Каждый раз, когда целевое утверждение не выполняется (нельзя найти сопоставимого факта), Пролог возвращается и пытается найти новое соответствие для соседа слева данной цели, начиная поиск с места, отмеченного соответствующим ему маркером. Кроме того, Пролог должен сначала расконкретизировать все переменные, которые были конкретизированы при достижении этой цели. Другими словами, когда Пролог ищет новое соответствие для цели, он должен «уничтожить» старое значение этих переменных. Если для цели, к рассмотрению которой был возврат справа, нельзя найти новое соответствие, то Пролог перейдет еще левее, постепенно приближаясь к левой границе конъюнкции. Если не удается найти новое соответствие для крайней слева цели, которая уже не имеет соседа слева, то в этом случае считается несогласуемой с базой данных вся конъюнкция целей в вопросе к Прологу. Такое поведение, когда Пролог неоднократно пытается согласовать (и вновь согласовать) цели, входящие в вопрос-конъюнкцию, называется поиском с возвратом (бектрекингом). В следующей главе дается краткое описание механизма возврата, а в гл. 4 проводится более полное и детальное рассмотрение этого процесса.

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

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

Упражнение 1.1. Продолжить разбор рассмотренного выше примера с помощью карандаша и бумаги, предположив, что вы ввели точку с запятой;, инициируя возврат для того, чтобы определить, существует ли еще что-нибудь, что нравится одновременно Джону и Мэри.

Рис. 1.1.

1.5. Правила

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


нравится(джон,альфред).

нравится(джон,бертран).

нравится(джон,чарлз).

нравится(джон,дейвид).

* * *


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

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

Я пользуюсь зонтом, если идет дождь.

Джон покупает вино, если оно дешевле, чем пиво.

Правила используются также для выражения определений, например:

X является птицей, если:

 X является живым существом и X имеет перья.

или

X является сестрой Y, если:

 X является женщино и X и Y имеют одних и тех же родителей.

В последних примерах мы использовали переменные X и Y. Важно помнить, что каждое вхождение переменной в правило обозначает один и тот же объект. Иначе мы разрушили бы саму суть определения. Например, используя приведенное выше определение птицы, мы не смогли бы показать, что Фред является птицей на основании того, что Фидо – это живое существо, а Мэри имеет перья. Этот принцип согласованной интерпретации переменных справедлив также и для правил в Прологе.

Правило – это некоторое общее утверждение об объектах и об отношениях между ними. Например, мы можем сказать, что Фред является птицей, если Фред является живым существом и Фред имеет перья, мы можем также сказать, что Бертрам является птицей, если Бертрам является живым существом и Бертрам имеет перья. Таким образом, мы допускаем, что при каждом новом использовании правила переменная обозначает новый, отличный от прежнего объект. Конечно, в рамках конкретного использования правила переменные интерпретируются согласованно, как на это указывалось выше.

Рассмотрим несколько примеров, начав с правила, содержащего одну переменную и конъюнкцию:

Джону нравится любой, кому нравится вино, или,

другими словами,

Джону нравится что-то, если чему-то нравится вино,

или, используя переменные,

Джону нравится X, если X нравится вино.

В Прологе правило состоит из заголовка и тела правила. Заголовок и тело соединяются с помощью символа :-, который состоит из двоеточия : и тире -. Символ ':-' читается если.

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


нравится(джон,X):- нравится(Х,вино).


Отметим, что правила также заканчиваются точкой. Заголовком этого правила является нравится(джон,Х). Заголовок правила описывает факт, для определения которого предназначено это правило. Тело правила, в данном случае нравится(Х,вино), описывает конъюнкцию целей, которые должны быть последовательно согласованы с базой данных, для того чтобы заголовок правила был истинным. Например, мы можем сделать Джона более разборчивым в выборе тех, кто ему нравится, просто добавив к телу правила еще несколько целевых утверждений, разделив их запятыми:


нравится(джон,X):- нравится(Х,вино), нравится(X,пища).


или, другими словами, Джону нравится любой, кому нравятся вино и пища. Или, предположим, что Джону нравится любая женщина, которой нравится вино:


нравится(джон,Х):- женщина(Х), нравится(Х,вино).


Всякий раз, когда мы имеем дело с правилом в Прологе, необходимо отмечать все вхождения переменных. В последнем примере переменная X использована три раза. Всякий раз, как переменная X конкретизируется некоторым объектом (ей присваивается значение), все вхождения X в пределах области действия этой переменной становятся конкретизированными. При каждом употреблении правила область действия переменной X – это все правило, начиная с заголовка и до точки '.' в конце этого правила. Так, если в приведенном выше правиле переменная X оказалась конкретизированной, принимая значение мэри, то Пролог попытается согласовать с базой данных целевые утверждения женщина(мэри) и нравится(мэри,вино).

Теперь, чтобы продемонстрировать правило, использующее более одной переменной, рассмотрим базу данных, содержащую факты о семействе королевы Виктории. Мы будем использовать предикат родители, имеющий три аргумента. родители(Х, Y, Z) означает: Родителями X являются Y и Z. Переменная Y обозначает мать, а переменная Z обозначает отца. Кроме того, мы будем использовать предикаты женщина и мужчина в их очевидном значении. Некоторая часть этой базы данных могла бы выглядеть следующим образом:


мужчина(альберт).

мужчина(эдуард).

женщина(алиса).

женщина(виктория).

родители(эдуард,виктория,альберт).

родители(алиса,виктория,альберт).


Здесь мы воспользуемся описанным ранее правилом является_сестрой. Правило определяет предикат является_сестрой, имеющий два аргумента, таким образом, что является_сестрой(X, Y) истинно, если X является сестрой Y. Обратим внимание на использование в имени предиката символа подчеркивания '_'. Хотя до сих пор не было дано полных правил конструирования имен, отметим, что допускается использование подчеркивания в именах, а более подробно об этом будет сказано в следующей главе. Тогда X является сестрой Y, если:

X является женщиной,

X имеет мать М и отца F и

Y имеет тех же мать и отца, что и X.

Это можно записать в виде следующего правила Пролога:


является_сестрой(X,Y):- женщина(X), родители(X,M,P), родители(Y,M,P).


Мы используем переменные M и F для обозначения матери и отца, хотя при желании мы могли бы использовать имена Мать и Отец. Отметим, что мы употребляем переменные, которые не появляются в заголовке правила. Эти переменные, M и F, обрабатываются таким же образом, как и любая другая переменная. Когда Пролог использует это правило, переменные M и F изначально будут неконкретизированными. Этим переменным будет присвоено некоторое значение в момент установления соответствия для предиката родители(X,M,F). Однако, как только они конкретизируются, становятся конкретизированными и все вхождения переменных M и F, соответствующие текущему использованию правила. Следующий пример должен помочь объяснить, как используются эти переменные. Давайте зададим вопрос:


?- является_сестрой(алиса,эдуард).


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

1. Сначала вопрос сопоставляется с единственным правилом для предиката является_сестрой, приведенным выше. При этом переменная X конкретизируется, принимая значение алиса, и переменная Y конкретизируется значением эдуард. Правило, с которым произошло сопоставление, отмечается маркером. Теперь Пролог пытается последовательно согласовать с базой данных три предиката, входящие в тело правила.

2. Так как на предыдущем шаге переменной X присвоено значение алиса, то первой целью является женщина(алиса). Истинность этого предиката следует из списка фактов, так что цель достигнута. Поскольку данная цель согласована, то Пролог отмечает соответствующее ей место в базе данных (третье утверждение в базе данных). При этом не произошло никаких присвоений значений переменным. Далее Пролог пытается согласовать следующую цель.

3. Теперь Пролог ищет соответствие для предиката родители(алиса,M,F), где переменные M и F сопоставимы с любыми аргументами, так как первоначально они неконкретизированы. Факт, с которым происходит сопоставление, есть родители(алиса, виктория,альберт), и тем самым вторая цель достигнута. Пролог отмечает маркером соответствующее место в базе данных (шестое утверждение сверху) и записывает, что M присвоено значение виктория, a F – значение альберт. (Если хотите, вы можете делать соответствующую запись над целевым утверждением в правиле.) Затем Пролог пытается найти соответствие для следующего предиката в правиле.

4. Теперь Пролог ищет в базе данных факт родители(эдуард,виктория,альберт), так как из запроса нам известно, что Y – это эдуард, а из предыдущего шага мы знаем, что M и F обозначают виктория и альберт. Эта цель достигается, поскольку найден подходящий факт (пятое утверждение сверху). Так как это последняя цель в конъюнкции, то и полное целевое утверждение является согласованным с базой данных, и тем самым доказано, что факт является_сестрой(алиса, эдуард) является истинным, Пролог отвечает да.

Предположим, мы хотим знать, является ли Алиса чьей-либо сестрой. Соответствующий вопрос на Прологе имеет вид


?- является_сестрой(алиса,X).


В ответ на вопрос Пролог выполняет следующие действия:

1. Вопрос сопоставляется с заголовком единственного правила для предиката является_сестрой. Переменная X, входящая в это правило, конкретизируется значением алиса. Так как переменная X в запросе неконкретизирована, то и переменная Y в правиле также будет неконкретизированной. Однако эти две переменные теперь становятся сцепленными. Как только одной из переменных присваивается некоторое значение, другая переменная становится конкретизированной тем же самым значением. Конечно, в данный момент они неконкретизированы.

2. Первая цель – женщина(алиса), которая достигается так же, как и в предыдущем примере.

3. Вторая цель – родители(алиса,М,F). Эта цель сопоставляется с родители(алиса,виктория,альберт). Переменные M и F становятся конкретизированными.

4. Так как переменная Y пока неизвестна, то третьей целью будет родители(Y,виктория,альберт), и она сопоставляется с родители(эдуард, виктория,альберт). Переменная Y конкретизируется значением эдуард.

5. Так как все целевые утверждения согласованы с базой данных, то тем самым согласовано и правило в целом, при этом переменная X (как известно из вопроса) равна алиса и Y равна эдуард. Учитывая, что Y (в правиле) является сцепленной с X (в вопросе), то X также конкретизирована значением эдуард. Пролог печатает Х=эдуард.

Как обычно, Пролог ожидает, пока вы сообщите ему, хотите ли вы найти все ответы на вопрос. Оказывается, что на данный вопрос имеется более одного ответа. Как Пролог находит оставшиеся ответы (ответ), является содержанием упражнения, приведенного в конце главы.

Как мы видели до сих пор, существуют два способа предоставить Прологу информацию относительно предиката, подобного предикату нравится. Мы можем сделать это, используя как факты, так и правила. В общем случае предикат будет определен смесью фактов и правил. Эти факты и правила, определяющие предикат, называются утверждениями[4]. Мы будем использовать слово утверждение в случаях, когда мы ссылаемся либо на факт, либо на правило.

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


может_украсть(P,T:- вор(P), нравится(P,T), ценный(T).


Предикат может_украсть, который имеет две переменные P и T, представляет отношение: некоторый человек P может украсть вещь T. Это правило зависит от утверждений, определяющих предикаты вор, нравится и ценный. Они могут быть представлены либо как факты, либо как правила в зависимости от того, что является более подходящим. Например, рассмотрим следующую базу данных, составленную в том числе из утверждений, обсуждавшихся ранее. Мы добавим к ним номера утверждений, заключенные между специальными скобками /*… */. Именно таким образом в Пролог-системе записывается комментарий. Комментарии игнорируются Пролог-системой, но мы можем добавить их в программу для удобства. В последующем обсуждении мы будем ссылаться на номера предложений, представленные в виде комментариев.

/*1*/ вор(джон).

/*2*/ нравится(мэри, пища).

/*3*/ нравится(мэри,вино).

/*4*/ нравится(джон,X):- нравится(X,вино).

/*5*/ может_украсть(X,Y):- вор(X), нравится(X,Y).

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

?- может_украсть(джон,Х).

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

1. Прежде всего Пролог ищет в базе данных утверждение, описывающее предикат может_украсть, и находит такое утверждение. Оно представлено в виде правила и имеет номер 5. Пролог отмечает это место в базе данных. Так как это утверждение является правилом, то, чтобы установить, согласуется ли заголовок правила с базой данных, необходимо попытаться согласовать с ней тело правила. Тогда переменной X в правиле 5 присваивается значение джон, которое берется из вопроса. Как и в предыдущих примерах, мы должны сопоставить неконкретизированные переменные (X в вопросе и Y в правиле), так что теперь они будут сцеплены. Если вы не уверены, что до конца понимаете, что это значит, то необходимо вернуться назад к примерам с предикатом является_сестрой(X, Y). Для того чтобы правило выполнилось, необходимо согласовать цели с базой данных. Таким образом, теперь проверяется на согласованность с базой данных первое утверждение вор(джон).

2. Эта цель достигается, так как факт вор(джон) содержится в базе данных (утверждение 1). Пролог отмечает это место в базе данных, и при этом присвоения значений переменным не происходит. Далее Пролог пытается достигнуть вторую цель, применяя утверждение 5. Так как X, как и ранее, обозначает джон, то теперь Пролог ищет нравится (джон, Y). Заметим, что к этому моменту Y остается неконкретизированной.

3. Цель нравится(джон, Y) сопоставляется с заголовком правила (утверждение 4). Переменная Y, входящая в цель, сцепляется с X в заголовке правила, и обе эти переменные остаются неконкретизированными. Чтобы доказать это правило, теперь ищется нравится(Х, вино).

4. Эта цель достигается, так как она сопоставляется с нравится (мэри,вино) - фактом, являющимся утверждением с номером 3. Так что теперь X становится мэри.

5. Так как цель в утверждении 4 достигнута, то согласовано и правило в целом. Факт нравится(джон, мэри) следует из утверждения 4, так как переменная Y в утверждении 5 сцеплена с X, и ей тоже присваивается значение мэри.

6. Утверждение 5 теперь согласуется с базой данных при Y, имеющем значение мэри. Так как переменная Y была сцеплена со вторым аргументом исходного вопроса, то переменная X в вопросе конкретизируется, принимая значение мэри. Приведем рассуждение, обосновывающее факт Джон может украсть Мэри:

Для того чтобы украсть что-либо, прежде всего Джон должен быть вором. Из утверждения 1 следует, что это имеет место. Далее, Джону должен нравиться похищаемый предмет. Из утверждения 4 мы видим, что Джону нравится любой, кому нравится вино. Из утверждения 3 мы видим, что Мэри нравится вино. Следовательно, Джону нравится Мэри. Поэтому оба условия для похищения некоторого объекта имеют место, а значит, Джон может украсть Мэри.

Заметим, что факт (утверждение 2) о том, что Мэри нравится пища, не имеет никакого отношения к данному конкретному запросу, так как он нигде не понадобился.

В приведенном примере мы повторно использовали переменные X и Y в различных утверждениях. Например, в правиле может_ украсть X обозначает объект, который может что-нибудь украсть. Но в правиле нравится X обозначает объект, которому что-то нравится. Для того чтобы приведенная программа имела смысл, в Прологе должна иметься возможность указывать, что X может обозначать различные вещи в различных употреблениях утверждений. Помните, что знание области действия переменной может разрешить любые неясности. Мы могли бы использовать более мнемоничные имена, чтобы попытаться предотвратить любые неясности, но мы используем простые имена, такие как X, чтобы продемонстрировать работу принципа области действия переменной.

1.6. Заключение и упражнения

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

• объявление фактов об объектах;

• задание вопросов относительно известных фактов;

• роль переменных и их области действия;

• конъюнкцию как способ описания и-условий;

• представление отношений в виде правил;

• общую схему поиска с механизмом возврата.

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

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

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

Упражнение 1.2. При применении правила является_сестрой к обсуждавшейся ранее базе данных, содержащей информацию о семействе королевы Виктории, может быть получено несколько ответов. Объясните, как могут быть получены все ответы и каковы они.

Упражнение 1.3. В основу этого упражнения положено одно из упражнений из книги Kowalski R. Logic for Problem Solving, North Holland, 1979. Предположим, что кем-то уже написаны на Прологе утверждения, определяющие следующие отношения: ...




Все права на текст принадлежат автору: У Клоксин, К Меллиш.
Это короткий фрагмент для ознакомления с книгой.
Программирование на языке ПрологУ Клоксин
К Меллиш