355 500 произведений, 25 200 авторов.

Электронная библиотека книг » У. Клоксин » Программирование на языке пролог » Текст книги (страница 11)
Программирование на языке пролог
  • Текст добавлен: 21 октября 2016, 18:46

Текст книги "Программирование на языке пролог"


Автор книги: У. Клоксин


Соавторы: К. Меллиш
сообщить о нарушении

Текущая страница: 11 (всего у книги 26 страниц)

ГЛАВА 6. ВСТРОЕННЫЕ ПРЕДИКАТЫ

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

Предикаты для ввода-вывода показывают, что встроенные предикаты могут иметь «побочные эффекты». Это значит, что при доказательстве согласованности целевого утверждения, содержащего такой предикат, помимо конкретизации аргументов предиката могут возникнуть дополнительные изменения. Это, естественно, не может случиться с предикатами, определенными на чистом Прологе. Другой важный факт, касающийся встроенных предикатов, состоит в том, что они могут быть определены только для аргументов конкретного вида. Например, рассмотрим предикат '‹' определенный таким образом, что Х‹Yвыполняется, если число Xменьше, чем число Y. Подобное отношение не может быть определено в Прологе без помощи посторонних средств, использующих некоторые знания о числах. Таким образом,  – это встроенный предикат, а его определение использует некоторые операции вычислительной машины, на которой реализована Пролог-система, для определения относительной величины чисел (представленных в виде двоичного кода или каким-либо иным способом).

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

6.1. Ввод новых утверждений

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

consult(X)

Встроенный предикат consultпредназначен для использования в тех ситуациях, когда вы хотите добавить утверждения из некоторого файла /или вводимые с терминала) к утверждениям, уже имеющимся в базе данных. Аргумент предиката должен быть атомом, указывающим имя файла, из которого должны браться утверждения. Какие литеры составляют допустимое имя файла, естественно, зависит от конкретной, используемой вами ЭВМ. Ниже приведены примеры возможной записи целевого утверждения с предикатом consultна различных ЭВМ:

?– consult(myfile).

?– consult('/us/gris/pl/chat').

?– consult('lib:iorout.pl'),

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

reconsult(X)

Предикат reconsultаналогичен предикату consult, за исключением того, что вводимые утверждения заменяютвсе имеющиеся утверждения для того же самого предиката. Вследствие этого reconsult удобно использовать для исправления ошибок в программе. Если вы вводите некоторые файлы с утверждениями и затем обнаруживаете, что одно из утверждений содержит ошибку, то вы можете исправить ее, и для этого нет необходимости вводить заново все файлы. Чтобы сделать это, вам необходимо ввести с помощью reconsultфайл, содержащий совокупность правильных утверждений для предиката, содержащего ошибку. Вы можете ввести исправления либо непосредственно с терминала (reconsult (user)), либо сначала отредактировать соответствующий файл, не выходя из Пролог-системы (такую возможность предоставляют не все реализации), и затем ввести этот файл с помощью reconsult. Конечно, при вводе исправленных утверждений с терминала содержание базы данных,с которой работает Пролог, изменится, но при этом исходный файл,содержащий первоначальные утверждения с ошибками, останется неизменным! В разд. 8.5 показано использование предикатов consultи reconsultв процессе разработки программы.

Списковая форма записи

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

?– [файл1,-файл2,'фред.1',-'билл.2'].

полностью эквивалентен следующему, но более длинному;

?– consult(файл1), reconsult(файл2), consult('фред:1'), reconsult('билл.2').

Списковая форма сводится к удобству записи, она не дает каких-либо дополнительных возможностей по сравнению с использованием предикатов consultи reconsult.Некоторые реализации Пролога могут использовать в списковой форме записи вместо знака '-' какой-нибудь иной знак, но эффект при этом останется прежним.

6.2. Выполнение и невыполнение целевого утверждения

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

true

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

fail

Это целевое утверждение никогда не согласуется с базой данных. Имеются две ситуации, когда этот предикат оказывается полезным. Одна из них – это использование комбинации !– fail,которая уже была описана в разд. 4.3. Конъюнкция целевых утверждений

…!, fail

применяется для того, чтобы указать, что если процесс выполнения дошел до этого момента, то можно больше не пытаться доказать (согласовать) данное целевое утверждение.Конъюнкция считается несогласованной благодаря наличию предиката fail,а родительское целевое утверждение не согласуется ввиду того, что использовано отсечение.

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

?– событие (X,Y), phh(Y), fail.

привело бы к печати всех событий, имеющихся в базе данных, рассмотренной в разд. 5.1, выбор событий и печать их краткого содержания выполняют предикаты событие и phh,при этом цель окажется несогласованной с базой данных. Еще одно применение failрассмотрено в разд. 7.13 (в определении предиката retrac-tall).

6.3. Классификация термов

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

var(X)

Целевое утверждение var(X)согласуется с базой данных, если на текущий момент Xявляется неконкретизированной переменной. Таким образом, возможен следующий диалог:

?– var(X).

да

?– var(23).

нет

?– X = Y, Y = 23, var(X).

нет

Неконкретизированная переменная может представлять часть некоторой структуры, которая еще не полностью заполнена. Примерами могут служить неотмеченные клетки на доске для игры в крестики-нолики, рассмотренной в разд. 4.3.3, и незаполненные части упорядоченного дерева, представляющего словарь в разд. 7.1. При работе с такими структурами предикат varочень, полезен при определении, являются ли некоторые части структуры уже заполненными или нет. Это может предотвратить «случайную» конкретизацию переменной при попытке анализа ее значения. Например, при работе со словарем, представленным в виде упорядоченного дерева, может потребоваться узнать, имеется ли уже вход для некоторого ключа, не создавая такой вход в случае его отсутствия. При игре в крестики-нолики может возникнуть необходимость определить, занята или нет некоторая клетка. Попытка сопоставить неконкретизированную переменную с « о» или « х» привела бы просто к тому, что соответствующий символ был бы помещен в клетку, соответствующую переменной.

nonvar(X)

Целевое утверждение nonvar(X)согласуется с базой данных, если Xна текущий момент не является неконкретизированной переменной. Предикат nonvarявляется, таким образом, противоположным по отношению к предикату var. Действительно, он может быть определен на Прологе следующим образом:

nonvar(X):– var(X),!, fail.

nonvar(_).


atom(X)

Целевое утверждение atom(X)согласуется с базой данных, если текущее значение Xявляется атомом в смысле языка Пролог. Как следствие возможен следующий диалог:

?– atom(23).

нет

?– atom(apples).

да

?– atom('/us/qris/pl. 123').

да

?– atom("этo строка").

нет

?– atom(X).

нет

?– atom(book(bronte,w_h,X)).

нет


integer(X)

Целевое утверждение integer(X)согласуется с базой данных, если на текущий момент Xобозначает целое число. Этот предикат можно использовать при определении простого предиката для упрощения арифметических выражений, где необходимо знать, является ли выражение целым числом (см., например, разд. 7.12).

atomic(X)

Целевое утверждение atomic(X)согласуется с базой данных, если на текущий момент Xобозначает либо целое число, либо атом. Предикат atomicможет быть определен через предикаты atomи integerследующим образом:

atomic(X):– atom(X).

atomic(X):– integer(X)

6.4. Работа с утверждениями как с термами

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

• Создавать структуру, представляющую утверждения в базе данных.

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

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

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

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

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

может рассматриваться как обычная структура с функтором нравится(имеющим два аргумента) и аргументами джони X.С другой стороны, правило можно рассматривать как структуру с главным функтором ':-'(с двумя аргументами). Этот функтор объявлен как инфиксный оператор. Первым аргументом является заголовок утверждения, а вторым – его тело. Так что

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

есть не что иное, как

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

– совершенно обычная структура. Далее, если правило содержит более одного целевого утверждения, то они считаются объединенными в структуры с функтором ',' (с двумя аргументами). Этот предикат также объявлен как инфиксный оператор. Так что

прародитель(Х, Z):– родитель(Х, Y), родитель(Y,Z)

есть в действительности просто

':-'(прародитель(Х,Z),Y(родитель(Х,Y),родитель(Y, Z))

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


listing (A)

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

?– [test].

test consulted

да

?– обр([a,b,c,d],X).

нет

?– listing(обр).

обр([],[]).

обр ([_44|_45],_38):-обр(_45,_47),присоединить(_47,[_44],_38).

да

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

clause(X, Y)

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

Заметим, что в то время как предикат clauseвсегда имеет аргумент, соответствующий телу утверждения, далеко не каждое утверждение действительно имеет тело. Если утверждение не имеет тела, то считается, что оно имеет фиктивное тело true.Мы называли такие утверждения «фактами». В той или иной степени конкретизируя Xи Y, можно искать либо все утверждения, соответствующие данному предикату с вполне определенным числом аргументов, либо все утверждения, соответствующие некоторому образцу. Так, например:

присоединить([], X, X).

присоединить([А|В]),С,[А|D]:– присоединить(В,С,D).

?– clause(присоединить(А,В,С),Y).

А=[], В =_23, С=_23, Y = true;

А = [_23|_24], В =_25, С = [_23|_26], Y = присоединить(_24,_25,_26);

нет

Предикат clauseочень полезен в том случае, если нам надо создать программы, анализирующие или исполняющие другие программы (см. разд. 7.13).

asserta(X), assertz(X)

Два встроенных предиката assertaи assertzпозволяют добавлять новые утверждения в базу данных. Оба предиката действуют в точности одинаковым образом, за тем исключением, что assertaдобавляет утверждение в началобазы данных, в то время как assertzдобавляет утверждение в ее конец.Это отличие можно легко запомнить, учитывая, что « а» является первой буквой английского алфавита, a « z» его последняя буква. При выполнении целевого утверждения asserta(X), Xдолжно иметь значением нечто, что можно представлять как утверждение; действительно, как и в случае clause, Xдолжно быть достаточно конкретизировано, чтобы можно было установить главный предикат. Необходимо подчеркнуть, что результат добавления в базу данных утверждения не устраняется при выполнении возврата. Следовательно, если мы использовали предикат assertaили assertzдля того, чтобы добавить новое утверждение, то это утверждение может быть удалено только в случае, если мы явно укажем это (используя предикат retract).

retract(X)

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

Так как аргумент Xсопоставляется с удаляемым утверждением, то имеется возможность получить точное представление об удаляемом утверждении, даже если Xисходно означал некоторую структуру, содержащую множество неконкретизированных переменных. Это позволяет использовать предикат retractвместо предиката clause, в ситуации когда найденное утверждение сразу же удаляется. Такая ситуация как раз имеет место в определении предиката генатом (разд. 7.8).

6.5. Создание структур и работа с компонентами структур

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

В некоторых программах мы не можем предвидеть заранее все возможные структуры. Это имеет место, например, при написании программы «красивой печати», которая могла бы печатать произвольные структуры языка Пролог, размещая их в нескольких строках и используя отступы. (См. разд. 5.1, где представлена такая программа для печати списков.) Так, например, возможно, мы захотели бы напечатать терм

книга(629,автор(бронте, эмили),вх)

следующим образом:

книга

 629

 автор

  бронте

  эмили

 вх

Важным моментом является то, что мы хотим, чтобы эта программа работала правильно, какую бы структуру мы ей ни задали. Понятно, что одна из возможностей сделать это – обеспечить отдельное утверждение для каждого функтора, какой только можно представить. Но это работа, которую мы никогда не завершим, потому что существует бесконечно много различных функторов! Написать подобную программу можно, используя встроенные предикаты для работы со структурами произвольного вида. Здесь мы опишем некоторые из них – это предикаты functor, argи ' =..'. Мы опишем также предикат name, выполняющий операции над атомами.

functor(T,F,N)

Предикат functorопределен таким образом, что functor(T,F,N)означает, что Тэто структура с функтором F, имеющим N аргументов.Этот предикат можно использовать двумя основными способами, В первом случае аргумент Туже имеет значение. Целевое утверждение считается несогласованным с базой данных, если Тне является ни атомом, ни структурой. Если Т– это атом или структура, то Fсопоставляется с функтором этой структуры, а Nприсваивается значение, равное числу аргументов функтора. Заметим, что в данном контексте считается, что атом – это структура с числом аргументов 0. Ниже приведено несколько примеров целевых утверждений с предикатом functor:

?– functor(f(a,b,g(Z)),F,N).

Z = _23, F = f ,N =3

?– functor(a+b,F,N).

F = +, N = 2

?– functor([a,b,c],F,N).

F =., N = 2

?– functor(apple,F,N).

F = apple, N = 0

?– functor([a,b,c],'.',3).

нет

?– functor([a,b,c],a,Z).

нет

Прежде чем перейти к обсуждению предиката arg,следует рассмотреть второй способ использования предиката functor.В этом случае первый аргумент целевого утверждения functor (Т, F, N)неконкретизирован. В этом случае два других аргумента должны быть конкретизированы, однозначно определяя функтор и число аргументов соответственно. Целевое утверждение такого вида всегда согласуется с базой данных, и в результате значением Тстановится структура с указанными функтором и числом аргументов. Таким образом, это некоторый способ созданияпроизвольных структур по заданным функтору структуры и числу ее аргументов. Аргументами такой структуры, созданной с помощью предиката functor,являются неконкретизированные переменные. Следовательно, эта структура будет сопоставима с любой другой структурой, имеющей тот же функтор и одинаковое число аргументов.

Предикат functorиспользуется для создания структуры в основном тогда, когда нам надо получить «копию» некоторой уже существующей структуры с новыми переменными в качестве аргументов. Мы можем ввести для этого предикат копирование,использующий functorкак целевое утверждение:

копирование(Старая, Новая):– functor(Cтapaя,F,N), functor(Hoвaя,F,N).

В этом определении подряд используются два целевых утверждения functor.Если целевое утверждение копированиеимеет конкретизированный первый аргумент и неконкретизированный второй, то произойдет следующее. Первое целевое утверждение functorбудет соответствовать первому способу использования этого предиката (так как первый аргумент этого предиката конкретизирован). Следовательно, Fи Nконкретизируются, получив в качестве значений функтор и число аргументов этой существующей структуры. Второе целевое утверждение functorсоответствует второму способу использования этого предиката. На этот раз первый аргумент неконкретизирован, и информация, задаваемая Fи N, используется для создания структуры Новая.Эта структура имеет те же функтор и число аргументов, что и Старая, но ее компонентами являются переменные. Таким образом, возможен следующий диалог:

?– копирование(sentence(np(n(john)), v(eats)),X).

X = sentence(_23,_24)

Мы используем подобную комбинацию целевых утверждений functorв определении предиката reconsultв разд. 7.13.

arg(N,T,A )

Предикат argвсегда должен использоваться с конкретизированными первым и вторым аргументами. Он применяется для доступа к конкретному аргументу структуры. Первый аргумент предиката argопределяет, какой аргумент структуры необходим. Второй аргумент определяет структуру, к аргументу которой необходим доступ. Пролог находит соответствующий аргумент и затем пытается сопоставить его с третьим аргументом предиката arg.Таким образом, цель arg(N,T,A)согласуется с базой данных, если N-й аргумент Тесть А. Давайте рассмотрим несколько целевых утверждений с arg.

?– аrg(2,отношение(джон,мать(джейн)),Х).

X = мать(джейн)

?– arg(1,a+(b+c),X).

X =а

?– arg(2,[a,b,c],X).

X = [b,c]

?-arg(l,a+(b+c),b).

нет

Иногда мы захотим использовать предикаты functorи argв ситуации, когда возможные структуры уже известны. Это связано с тем, что структура может иметь так много аргументов, что просто неудобно каждый раз перечислять их все. Рассмотрим пример, в котором структуры используются для описания книг. Мы могли бы иметь отдельную компоненту для названия книги, ее автора, издательства, года издания и так далее. Будем считать, что результирующая структура имеет четырнадцать компонент. Мы могли бы написать следующие полезные определения:

является _ книгой(книга(_,_,_,_,_,_,_,_,_,_,_,_,_,_)).

название(книга(Т,_,_,_,_,_,_,_,_,_,_,_,_,_),Т).

автор(книга(_,А,_,_,_,_,_,_,_,_,_,_,_,_),А).

. . .

В действительности мы можем записать это значительно более компактно следующим образом:

является_книгой(Х):– functor(X, книга, 14).

название(Х,Т):– является_книгой(Х), arg(1,X,T).

автор(Х,А):– является_книгой(Х), arg(2,X,T).

. . .

X=..L

Предикаты functorи argдают один из способов создания произвольных структур и доступа к их аргументам. Предикат «=..» предоставляет альтернативный способ, полезный в том случае, когда необходимо одновременно получить все аргументы структуры или создать структуру по заданному списку ее аргументов. Целевое утверждение X=..Lозначает, что L есть список, состоящий из функтора структуры X, за которым следуют аргументы X. Такое целевое утверждение может быть использовано двумя способами, так же как и целевое утверждение functor.Если Xуже имеет значение, то Пролог создает соответствующий список и пытается сопоставить его с L. Напротив, если Xнеконкретизировано, то список будет использован для формирования соответствующей структуры, которая станет значением X. В этом случае голова списка должна быть атомом (этот атом станет функтором X). Ниже приведено несколько примеров целевых утверждений, содержащих =..:

?– имя(а,b,с) =.. X.

X = [имя,а,b,с]

?– присоединить([А|В],С, [A|D]) =..L.

A = _2, В = _3, С = _4, D = _5, L = [присоединить,[_2|_3],_4,[_2|_5]]

?– [a,b,c,d] =..L.

L = ['.',a,[b,c,d]].

?– (a+b) =.. L.

L = [+,a,b].

?– (a+b) =..

[+,A,B] A = а, В = b

?– [a,b,c,d] =..

[A|B] A = '.', В = [a,[b,c,d]]

?– X =.. [a,b,c,d]

X = a(b,c,d).

?– X =.. [присоединить,[a,b,],[c],[a,b,c]].

X = присоединить([а,b],[с],[а,b,с])

Примеры использования предиката =.. приведены в разд. 7.12.

name(А,L)

В то время как предикаты functor, argи =..используются для формирования произвольных структур и доступа к их аргументам, предикат nameиспользуется для работы с произвольными атомами. Предикат nameсопоставляет атому список литер (их ASCII кодов), из которых состоит этот атом. Данный предикат можно использовать как для определения литер, составляющих указанный атом, так и для определения атома, содержащего заданные литеры. Целевое утверждение name(A, L)означает, что литеры, образующие атом А, являются элементами списка L. Если аргументу А уже присвоено значение, то Пролог создает список литер и пытается сопоставить его с L. В противном случае Пролог использует список Lдля создания атома, который станет значением А. Приведем примеры использования предиката name:

?– name(apple,X).

X = [97,112,112,108,100]

?– name(X,[97,l12,112,108,100]).

X = apple

?– name(apple,"apple").

да

?– name(apple,"pear").

нет

В разд. 9.5 предикат nameиспользуется для доступа к внутренней структуре слов английского языка, представляемых атомами Пролога.


    Ваша оценка произведения:

Популярные книги за неделю